Commit 7fa7ff83 authored by eric pellegrini's avatar eric pellegrini

Many modifications to make the first job work

parent 98f7f78f
import abc
class _Meta(type):
'''
Metaclass that allows to use the __getitem__ method at a class level for the class that has been built.
The class that uses this metaclass must define a class attribute named _registry that will be used
by the __getitem__ method.
'''
def __getitem__(self, item):
"""
Returns a given item stored in the class registry
"""
return self._registry[item]
class ClassRegistry(abc.ABCMeta):
'''
Metaclass that registers the subclasses of bases classes.
The internal registry is defined as a nested dictionary whose keys
are the |type| class attribute of the base classes and values another dictionary
whose keys are the |type| class attribute of the subclasses and values are the corresponding
class instances.
Hence any base or child class that does not define |type| class attribute will not be resgistered.
'''
__metaclass__ = _Meta
__interfaces = []
_registry = {}
def __init__(self, name, bases, namespace):
'''
Constructor of a class metaclassed by ClassFactory
:param name: the name of the class to be built by this metaclass
:param bases: the base classes of the class to be built by this metaclass
:param namespace: the attributes and methods of the class to be built by this metaclass
'''
super(ClassRegistry, self).__init__(name, bases, namespace)
# Get the typ of the class
typ = getattr(self, 'type', None)
if typ is None:
return
metaClass = namespace.get("__metaclass__", None)
if metaClass is ClassRegistry:
ClassRegistry.__interfaces.append(self)
ClassRegistry._registry[typ] = {}
else:
for interface in ClassRegistry.__interfaces:
if issubclass(self, interface):
ClassRegistry._registry[interface.type][typ] = self
break
@classmethod
def info(cls, interface):
'''
Returns informations about the subclasses of a given base class stored in the registry.
:param cls: the ClassRegsitry instance
:param interface: the name of base class of whom information about its subclasses is requested
'''
if not cls._registry.has_key(interface):
return "The interface " + interface + " is not registered"
import inspect
import os
# Dictionnay whose keys are the package names and values and list of (job name, job path) stored in the corresponding package.
packages = {}
# Loop over the registry items.
for k, v in cls._registry[interface].items():
# Get the module corresponding to the job class.
mod = inspect.getmodule(v)
# The package hosting the module.
modPackage = mod.__package__
# The module file.
modFilename = mod.__file__
# If no package could be found, guess a name using the directory name of the module file.
if modPackage is None:
modPackage = os.path.split(os.path.dirname(modFilename))[1]
# Update the packages dictionary.
if packages.has_key(modPackage):
packages[modPackage].append([k, v.__name__])
else:
packages[modPackage] = [[k, v.__name__]]
contents = []
# Print the contents of the packages dictionary.
contents.append("="*130)
contents.append("%-50s %-40s %-s" % ("Package", "Name", "Class"))
contents.append("="*130)
for k, v in sorted(packages.items()):
for vv in sorted(v):
contents.append("%-50s %-40s %-s" % (k, vv[0], vv[1]))
contents.append('-' * 130)
contents = "\n".join(contents)
return contents
import logging
import sys
class Logger(object):
levels = {"debug" : logging.DEBUG,
"info" : logging.INFO,
"warning" : logging.WARNING,
"error" : logging.ERROR,
"fatal" : logging.CRITICAL,
"critical" : logging.FATAL
}
def __call__(self, message, level="info", loggers=None):
lvl = Logger.levels.get(level, None)
# If the logging level is unkwnown, skip that log
if lvl is None:
return
if loggers is None:
loggers = logging.Logger.manager.loggerDict.keys()
else:
loggers = [n for n in loggers if logging.Logger.manager.loggerDict.has_key(n)]
for n in loggers:
logging.getLogger(n).log(lvl, message)
def start(self, logger=None):
from nMOLDYN import _nmoldyn_excepthook
sys.excepthook = _nmoldyn_excepthook
if loggers is None:
loggers = logging.Logger.manager.loggerDict.keys()
else:
loggers = [n for n in loggers if logging.Logger.manager.loggerDict.has_key(n)]
for n in loggers:
logging.getLogger(n).disabled = False
def stop(self, loggers=None):
sys.excepthook = _sys_excepthook
if loggers is None:
loggers = logging.Logger.manager.loggerDict.keys()
else:
loggers = [n for n in loggers if logging.Logger.manager.loggerDict.has_key(n)]
for n in loggers:
logging.getLogger(n).disabled = True
def set_level(self, level, loggers=None):
lvl = Logger.levels.get(level, None)
if lvl is None:
return
if loggers is None:
loggers = logging.Logger.manager.loggerDict.keys()
else:
loggers = [n for n in loggers if logging.Logger.manager.loggerDict.has_key(n)]
for loggerName in loggers:
logging.getLogger(loggerName).setLevel(lvl)
def add_logger(self, name, handler, level="error"):
if logging.Logger.manager.loggerDict.has_key(name):
return
logging.getLogger(name).addHandler(handler)
self.set_level(level, loggers=[name])
......@@ -524,15 +524,15 @@ def initializeMasterProcess(label, slave_script=None, slave_module=None,
source = file(slave_script).read()
else:
source = """
import nMOLDYN.DistributedComputing.MasterSlave
import MDANSE.DistributedComputing.MasterSlave
from %s import *
""" % slave_module
if debug:
source += "print 'Slave definitions:'\n"
source += "print dir()\n"
source += "nMOLDYN.DistributedComputing.MasterSlave.debug=True\n"
source += "MDANSE.DistributedComputing.MasterSlave.debug=True\n"
source += """
nMOLDYN.DistributedComputing.MasterSlave.startSlaveProcess()
MDANSE.DistributedComputing.MasterSlave.startSlaveProcess()
"""
process.task_manager.storeData(slave_code = source,
cwd = os.getcwd())
......
......@@ -4,12 +4,12 @@ Functions:
* do_run_step: performs the analysis step by step.
"""
# Define (or import) all the task handlers.
# Define (or import) all the task handlers.
def do_run_step(job, step):
return job.run_step(step)
from nMOLDYN.DistributedComputing.MasterSlave import startSlaveProcess
from MDANSE.DistributedComputing.MasterSlave import startSlaveProcess
startSlaveProcess(master_host="localhost:%d")
......@@ -51,7 +51,7 @@ class Configurable(object):
If not found raise a ConfigurationError.
"""
if self._configurators.has_key(name):
if self.configurators.has_key(name):
return self._configuration.setdefault(name,{})
raise ConfigurationError("The item %r is not valid for this configuration." % name)
......@@ -110,7 +110,7 @@ class Configurable(object):
info = []
for configurator in self._configuration:
for configurator in self._configuration.values():
info.append(configurator.get_information())
......
'''
MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
------------------------------------------------------------------------------------------
Copyright (C)
2015- Eric C. Pellegrini Institut Laue-Langevin
BP 156
6, rue Jules Horowitz
38042 Grenoble Cedex 9
France
pellegrini[at]ill.fr
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Created on Mar 23, 2015
@author: pellegrini
'''
import abc
import numpy
from MDANSE import REGISTRY
from MDANSE.Framework.Configurables.Configurable import Configurable
from MDANSE.Framework.Configurables.Configurators import ConfiguratorsDict
from MDANSE.Core.Error import Error
class InstrumentResolutionError(Error):
pass
class InstrumentResolution(Configurable):
__metaclass__ = REGISTRY
type = "instrument resolution"
def __init__(self):
Configurable.__init__(self)
self._frequencyWindow = None
self._timeWindow = None
@abc.abstractmethod
def set_kernel(self, frequencies, dt, parameters=None):
pass
@property
def frequencyWindow(self):
if self._frequencyWindow is None:
raise InstrumentResolutionError("Undefined frequency window")
return self._frequencyWindow
@property
def timeWindow(self):
if self._timeWindow is None:
raise InstrumentResolutionError("Undefined time window")
return self._timeWindow
class IdealInstrumentResolution(InstrumentResolution):
"""Defines an ideal instrument resolution with a Dirac response
"""
type = 'ideal'
configurators = ConfiguratorsDict()
__doc__ += configurators.build_doc()
def set_kernel(self, frequencies, dt):
self._frequencyWindow = numpy.zeros(len(frequencies), dtype=numpy.float64)
self._frequencyWindow[len(frequencies)/2] = 1.0
self._timeWindow = numpy.ones(len(frequencies), dtype=numpy.float64)
class GaussianInstrumentResolution(InstrumentResolution):
"""Defines an instrument resolution with a gaussian response
"""
type = 'gaussian'
configurators = ConfiguratorsDict()
configurators.add_item('mu', 'float', default=0.0)
configurators.add_item('sigma', 'float', default=1.0)
__doc__ += configurators.build_doc()
def set_kernel(self, frequencies, dt):
mu = self._configuration["mu"]["value"]
sigma = self._configuration["sigma"]["value"]
self._frequencyWindow = (1.0/(sigma*numpy.sqrt(2.0*numpy.pi)))*numpy.exp(-0.5*((frequencies-mu)/sigma)**2)
self._timeWindow = numpy.fft.fftshift(numpy.abs(numpy.fft.ifft(self._frequencyWindow))/dt)
class LorentzianInstrumentResolution(InstrumentResolution):
"""
Defines an instrument resolution with a lorentzian response
"""
type = 'lorentzian'
configurators = ConfiguratorsDict()
configurators.add_item('mu', 'float', default=0.0)
configurators.add_item('sigma', 'float', default=1.0)
__doc__ += configurators.build_doc()
def set_kernel(self, frequencies, dt):
mu = self._configuration["mu"]["value"]
sigma = self._configuration["sigma"]["value"]
fact = 0.5*sigma
self._frequencyWindow = (1.0/numpy.pi)*(fact/((frequencies-mu)**2 + fact**2))
self._timeWindow = numpy.fft.fftshift(numpy.abs(numpy.fft.ifft(self._frequencyWindow))/dt)
class PseudoVoigtInstrumentResolution(InstrumentResolution):
"""Defines an instrument resolution with a pseudo-voigt response
"""
type = 'pseudo-voigt'
configurators = ConfiguratorsDict()
configurators.add_item('eta','float', mini=0.0, maxi=1.0, default=0.5)
configurators.add_item('mu_lorentzian','float', default=0.0)
configurators.add_item('sigma_lorentzian','float', default=1.0)
configurators.add_item('mu_gaussian','float', default=0.0)
configurators.add_item('sigma_gaussian','float', default=1.0)
__doc__ += configurators.build_doc()
def set_kernel(self, frequencies, dt):
eta = self._configuration["eta"]["value"]
muL = self._configuration["mu_lorentzian"]["value"]
sigmaL = self._configuration["sigma_lorentzian"]["value"]
muG = self._configuration["mu_gaussian"]["value"]
sigmaG = self._configuration["sigma_gaussian"]["value"]
gContribution = (1.0/(sigmaG*numpy.sqrt(2.0*numpy.pi)))*numpy.exp(-0.5*((frequencies-muG)/sigmaG)**2)
fact = 0.5*sigmaL
lContribution = (1.0/numpy.pi)*(fact/((frequencies-muL)**2 + fact**2))
self._frequencyWindow = eta*lContribution + (1.0-eta)*gContribution
self._timeWindow = numpy.fft.fftshift(numpy.abs(numpy.fft.ifft(self._frequencyWindow))/dt)
class TriangularInstrumentResolution(InstrumentResolution):
"""Defines an instrument resolution with a triangular response
"""
type = 'triangular'
configurators = ConfiguratorsDict()
configurators.add_item('mu', 'float', default=0.0)
configurators.add_item('sigma', 'float', default=1.0)
__doc__ += configurators.build_doc()
def set_kernel(self, frequencies, dt):
mu = self._configuration["mu"]["value"]
sigma = self._configuration["sigma"]["value"]
val = numpy.abs(frequencies-mu) - sigma
self._frequencyWindow = numpy.where( val >= 0, 0.0, -val/sigma**2)
self._timeWindow = numpy.fft.fftshift(numpy.abs(numpy.fft.ifft(self._frequencyWindow))/dt)
class SquareInstrumentResolution(InstrumentResolution):
"""Defines an instrument resolution with a square response
"""
type = 'square'
configurators = ConfiguratorsDict()
configurators.add_item('mu', 'float', default=0.0)
configurators.add_item('sigma', 'float', default=1.0)
__doc__ += configurators.build_doc()
def set_kernel(self, frequencies, dt):
mu = self._configuration["mu"]["value"]
sigma = self._configuration["sigma"]["value"]
self._frequencyWindow = numpy.where((numpy.abs(frequencies-mu)-sigma) > 0,0.0,1.0/(2.0*sigma))
self._timeWindow = numpy.fft.fftshift(numpy.abs(numpy.fft.ifft(self._frequencyWindow))/dt)
if __name__ == "__main__":
res = REGISTRY["instrument resolution"]["square"]()
res.setup({"mu":2.0,"sigma":1.0})
res.set_kernel(numpy.array([1,2,3,4,5,6,7,8]),0.1)
This diff is collapsed.
This diff is collapsed.
import glob
import os
for module in glob.glob(os.path.join(os.path.dirname(__file__),'*.py')):
module = os.path.basename(module)
if module == '__init__.py':
continue
module = os.path.splitext(module)[0]
# Any error that may occur here has to be caught. In such case the module is skipped.
try:
__import__(module, locals(), globals())
except:
continue
'''
MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
------------------------------------------------------------------------------------------
Copyright (C)
2015- Eric C. Pellegrini Institut Laue-Langevin
BP 156
6, rue Jules Horowitz
38042 Grenoble Cedex 9
France
pellegrini[at]ill.fr
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Created on Mar 23, 2015
@author: pellegrini
'''
import cPickle
import os
import time
from MDANSE import PLATFORM, REGISTRY
from MDANSE.Core.Error import Error
from MDANSE.Core.Singleton import Singleton
class UserDefinableError(Error):
pass
class UserDefinitionsError(Error):
pass
class UnicodeDict(dict):
def __contains__(self, item):
if isinstance(item,basestring):
return super(UnicodeDict,self).__contains__(unicode(item))
else:
return super(UnicodeDict,self).__contains__(item)
def __setitem__(self, item, value):
if isinstance(item,basestring):
super(UnicodeDict,self).__setitem__(unicode(item),value)
else:
super(UnicodeDict,self).__setitem__(item,value)
class UserDefinable(dict):
'''
Base class for user definable objects. User definable objects are objects used in nmoldyn for
storing information that can be reused later when setting up jobs (e.g. k-vectors defintion,
atom selection ...). A user definable object is a dictionary with a predefined set of keys that
depends on the user definable object. Object serialization is the underlying mechanism used to
save those objets and is done using cPickle module.
'''
# Any user definable object will be registered at nmoldyn startup.
__metaclass__ = REGISTRY
# The base class has no type (hence it will not be registered)
type = "user-definable"
# The base class has no predefined set keywords
_keywords = []
def __init__(self, target, **kwargs):
'''
The constructor
'''
self._target = target
self._creationTime = time.ctime()
self._keywords = self._keywords
for k in self._keywords:
try:
self[k] = kwargs[k]
except KeyError:
raise UserDefinableError("Incomplete user definable object: missing %r key" % k)
@property
def target(self):
return self._target
@property
def keywords(self):
return self._keywords
@property
def creationTime(self):
return self._creationTime
def __setitem__(self, item,value):
# It is not possible to set directly a key of a user definable object
if item in self._keywords:
super(UserDefinable,self).__setitem__(item, value)
def __str__(self):
'''
Return the informal representation of a user definable object
'''
info = ["Created on: %s\n" % self.creationTime] + ["%s:\n%s\n" % (k,self[k]) for k in self._keywords]
return "".join(info)
class DefineAtomSelection(UserDefinable):
'''
The user definable object used for storing atom selection.
'''
type = "atom_selection"
_keywords = ['expression','indexes']
class DefineAtomTransmutation(UserDefinable):
'''
The user definable object used for storing atom transmutation.
'''
type = "atom_transmutation"
_keywords = ['expression','indexes','element']
class DefineQVectors(UserDefinable):
'''
The user definable object used for storing k vectors.
'''
type = "q_vectors"
_keywords = ['generator', 'parameters', 'q_vectors', 'is_lattice']
class DefineAxisSelection(UserDefinable):
'''
The user definable object used for storing axis selection.
'''
type = "axis_selection"
_keywords = ['molecule','endpoint1','endpoint2']
class DefineBasisSelection(UserDefinable):
'''
The user definable object used for storing basis selection.
'''
type = "basis_selection"
_keywords = ['molecule','origin','x_axis','y_axis']
class UserDefinitions(UnicodeDict):
'''
This class is used to register, save and delete UD (UD for User Definition).
Basically a UD file is a cPickle file that must store a dictionary of definitions related to a target file.
The target file can be any kind of file on which some extra information should be attached.
For instance, if the target file is a trajectory, the UD file may contains selected atoms,
center or axis that can be used for further analysis in new nMolDyn sessions.
'''
__metaclass__ = Singleton
_path = os.path.join(PLATFORM.application_directory(),"nmoldyn_user_definitions.ud")
def restore_state(self):
if not os.path.exists(UserDefinitions._path):
return