Commit ccb98160 authored by eric pellegrini's avatar eric pellegrini
Browse files

Modified the configure method by removing the configuration argument.

This one is now set at __init__
parent 2d9a92a9
......@@ -33,8 +33,8 @@ Created on Mar 30, 2015
import collections
import operator
import numpy
from MDANSE import ELEMENTS
from MDANSE.Framework.UserDefinitionStore import UD_STORE
from MDANSE.Framework.Configurators.IConfigurator import IConfigurator, ConfiguratorError
from MDANSE.Framework.AtomSelectionParser import AtomSelectionParser
......@@ -52,28 +52,38 @@ class AtomSelectionConfigurator(IConfigurator):
This configurator allows the selection of a specific set of atoms on which the analysis will be performed.
Without any selection, all the atoms stored into the trajectory file will be selected.
After the call to :py:meth:`~MDANSE.Framework.Configurators.AtomSelectionConfigurator.AtomSelectionConfigurator.configure` method
the following keys will be available for this configurator
#. value: the input value used to configure this configurator
#. indexes: the sorted (in increasing order) MMTK indexes of the selected atoms
#. n_selected_atoms: the number of selected atoms
#. elements: a nested-list of the chemical symbols of the selected atoms. The size of the nested list depends on the
grouping_level selected via :py:class:`~MDANSE.Framework.Configurators.GroupingLevelConfigurator.GroupingLevelConfigurator`
configurator.
:note: this configurator depends on 'trajectory' and 'grouping_level' configurators to be configured
:note: this configurator depends on :py:class:`~MDANSE.Framework.Configurators.MMTKTrajectoryConfigurator.MMTKTrajectoryConfigurator`
and :py:class:`~MDANSE.Framework.Configurators.GroupingLevelConfigurator.GroupingLevelConfigurator` configurators to be configured
'''
type = 'atom_selection'
_default = "all"
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
The value must be a string that can be either an atom selection string or a valid user
definition.
:param configuration: the current configuration
:type configuration: a MDANSE.Framework.Configurable.Configurable object
:param value: the input value
:type value: str
'''
trajConfig = configuration[self._dependencies['trajectory']]
trajConfig = self._configurable[self._dependencies['trajectory']]
if value is None:
value = ['all']
......@@ -86,97 +96,51 @@ class AtomSelectionConfigurator(IConfigurator):
self["value"] = value
self["indexes"] = []
indexes = set()
for v in value:
if UD_STORE.has_definition(trajConfig["basename"],"atom_selection",v):
ud = UD_STORE.get_definition(trajConfig["basename"],"atom_selection",v)
self["indexes"].extend(ud["indexes"])
indexes.update(ud["indexes"])
else:
parser = AtomSelectionParser(trajConfig["instance"].universe)
self["indexes"].extend(parser.parse(v))
indexes.update(parser.parse(v))
indexes = sorted(list(indexes))
self["indexes"].sort()
self["n_selected_atoms"] = len(self["indexes"])
atoms = sorted(trajConfig["universe"].atomList(), key = operator.attrgetter('index'))
selectedAtoms = [atoms[idx] for idx in self["indexes"]]
self["elements"] = [[at.symbol] for at in selectedAtoms]
if self._dependencies.has_key("grouping_level"):
self.group(selectedAtoms, configuration[self._dependencies['grouping_level']]['value'])
else:
self.group(selectedAtoms)
self.set_contents()
@staticmethod
def find_parent(atom, level):
'''
Retrieve recursively the parent of a given MMTK atom at a given level.
For example, a level of 1 will return the direct parent of the atom.
:note: this is a static method
:param atom: the atom for which the parent is searched for
:type atom: MMTK.Atom object
:param level: the level of the parent
:type level: int
'''
for _ in range(level):
atom = atom.parent
return atom
selectedAtoms = [atoms[idx] for idx in indexes]
self["selection_length"] = len(indexes)
self['elements'] = [[at.symbol] for at in selectedAtoms]
self['indexes'] = [[idx] for idx in indexes]
self['names'] = [at.symbol for at in selectedAtoms]
self['unique_names'] = sorted(set(self['names']))
self['masses'] = [[ELEMENTS[n,'atomic_weight']] for n in self['names']]
def get_natoms(self):
nAtomsPerElement = {}
for v in self["names"]:
if nAtomsPerElement.has_key(v):
nAtomsPerElement[v] += 1
else:
nAtomsPerElement[v] = 1
return nAtomsPerElement
def group(self, atoms, level="atom"):
'''
Group the selected atoms according to a given granularity and update
the configurator with the grouping results.
:param atoms: the atoms for
:type atoms: list of MMTK.Atom
:param level: the level of granularity at which the atoms should be grouped
:type level: str
'''
groups = collections.OrderedDict()
for at in atoms:
lvl = LEVELS[level][at.topLevelChemicalObject().__class__.__name__.lower()]
parent = self.find_parent(at,lvl)
groups.setdefault(parent,[]).append(at.index)
self["groups"] = groups.values()
self["n_groups"] = len(self["groups"])
if level != "atom":
self["elements"] = [["dummy"]]*self["n_groups"]
self["level"] = level
def get_indexes(self):
indexesPerElement = {}
for i,v in enumerate(self["names"]):
if indexesPerElement.has_key(v):
indexesPerElement[v].extend(self['indexes'][i])
else:
indexesPerElement[v] = self['indexes'][i]
self.set_contents()
def set_contents(self):
'''
Sets the contents of the atom selection.
'''
self["contents"] = collections.OrderedDict()
self['index_to_symbol'] = collections.OrderedDict()
for i, group in enumerate(self["elements"]):
for j, el in enumerate(group):
self["contents"].setdefault(el,[]).append(self["groups"][i][j])
self['index_to_symbol'][self["groups"][i][j]] = el
for k,v in self["contents"].items():
self["contents"][k] = numpy.array(v,dtype=numpy.int32)
return indexesPerElement
self["n_atoms_per_element"] = dict([(k,len(v)) for k,v in self["contents"].items()])
self['n_selected_elements'] = len(self["contents"])
def get_information(self):
'''
Returns some informations the atom selection.
......@@ -190,8 +154,6 @@ class AtomSelectionConfigurator(IConfigurator):
info = []
info.append("Number of selected atoms:%d" % self["n_selected_atoms"])
info.append("Level of selection:%s" % self["level"])
info.append("Number of selected groups:%d" % self["n_groups"])
info.append("Selected elements:%s" % self["contents"].keys())
return "\n".join(info)
\ No newline at end of file
......@@ -53,7 +53,7 @@ class AtomTransmutationConfigurator(IConfigurator):
_default = None
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
......@@ -65,14 +65,12 @@ class AtomTransmutationConfigurator(IConfigurator):
selection to the target chemical element stored in the 2nd element
#. str: the transmutation will be performed by reading the corresponding user definition
:param configuration: the current configuration
:type configuration: MDANSE.Framework.Configurable.Configurable
:param value: the input value
:type value: None or (str,str)-dict or str
'''
self["value"] = value
self["value"] = value
# if the input value is None, do not perform any transmutation
if value is None:
return
......@@ -80,13 +78,11 @@ class AtomTransmutationConfigurator(IConfigurator):
if not isinstance(value,(list,tuple)):
raise ConfiguratorError("Invalid input value.")
self["atom_selection"] = configuration[self._dependencies['atom_selection']]
if self["atom_selection"]["level"] != "atom":
raise ConfiguratorError("the atom transmutation can only be set with a grouping level set to %r" % 'atom', self)
trajConfig = configuration[self._dependencies['trajectory']]
trajConfig = self._configurable[self._dependencies['trajectory']]
parser = AtomSelectionParser(trajConfig["instance"].universe)
parser = AtomSelectionParser(trajConfig["instance"].universe)
self._nTransmutatedAtoms = 0
for expression,element in value:
......@@ -96,17 +92,18 @@ class AtomTransmutationConfigurator(IConfigurator):
if UD_STORE.has_definition(trajConfig["basename"],"atom_selection",expression):
ud = UD_STORE.get_definition(trajConfig["basename"],"atom_selection",expression)
self.transmutate(configuration, ud["indexes"], element)
indexes = ud["indexes"]
else:
indexes = parser.parse(expression)
self.transmutate(configuration, indexes, element)
def transmutate(self, configuration, selection, element):
self.transmutate(indexes, element)
self._nTransmutatedAtoms += len(indexes)
def transmutate(self, selection, element):
'''
Transmutates a set of atoms to a given element
:param configuration: the current configuration
:type configuration: MDANSE.Framework.Configurable.Configurable
:param selection: the indexes of the atoms to be transmutated
:type selection: list of int
:param element: the symbol of the element to which the selected atoms should be transmutated
......@@ -115,15 +112,15 @@ class AtomTransmutationConfigurator(IConfigurator):
if element not in ELEMENTS:
raise ConfiguratorError("the element %r is not registered in the database" % element, self)
atomSelConfigurator = self._configurable[self._dependencies['atom_selection']]
for idx in selection:
pos = self["atom_selection"]["groups"].index([idx])
self["atom_selection"]["elements"][pos] = [element]
# Update the current configuration according to the changes triggered by
# atom transumutation
configuration[self._dependencies['atom_selection']].set_contents()
atomSelConfigurator["names"][idx] = element
atomSelConfigurator["elements"][idx] = [element]
atomSelConfigurator['unique_names'] = sorted(set(atomSelConfigurator['names']))
def get_information(self):
'''
Returns some informations the atoms selected for being transmutated.
......@@ -136,6 +133,6 @@ class AtomTransmutationConfigurator(IConfigurator):
return "Not configured yet"
if self["value"] is None:
return "No atoms selected for deuteration"
return "No atoms selected for transmutation"
return "Number of selected atoms for deuteration:%d\n" % self["atom_selection"]["n_selected_atoms"]
\ No newline at end of file
return "Number of transmutated atoms:%d\n" % self._nTransmutatedAtoms
\ No newline at end of file
......@@ -47,7 +47,7 @@ class AtomsListConfigurator(IConfigurator):
_default = None
def __init__(self, name, nAtoms=2, **kwargs):
def __init__(self, configurable, name, nAtoms=2, **kwargs):
'''
Initializes the configurator.
......@@ -57,7 +57,7 @@ class AtomsListConfigurator(IConfigurator):
:type nAtoms: int
'''
IConfigurator.__init__(self, name, **kwargs)
IConfigurator.__init__(self, configurable, name, **kwargs)
self._nAtoms = nAtoms
......@@ -66,20 +66,18 @@ class AtomsListConfigurator(IConfigurator):
return self._nAtoms
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
The value must be a string that can be either an atom selection string or a valid user
definition.
:param configuration: the current configuration
:type configuration: a MDANSE.Framework.Configurable.Configurable object
:param value: the input value
:type value: str
'''
trajConfig = configuration[self._dependencies['trajectory']]
trajConfig = self._configurable[self._dependencies['trajectory']]
if UD_STORE.has_definition(trajConfig["basename"],"%d_atoms_list" % self._nAtoms,value):
molecule,atoms = UD_STORE.get_definition(trajConfig["basename"],"%d_atoms_list" % self._nAtoms,value)
......
......@@ -47,7 +47,7 @@ class AxisSelection(IConfigurator):
_default = None
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
......@@ -64,7 +64,7 @@ class AxisSelection(IConfigurator):
:type value: tuple or str
'''
trajConfig = configuration[self._dependencies['trajectory']]
trajConfig = self._configurable[self._dependencies['trajectory']]
if UD_STORE.has_definition(trajConfig["basename"],"axis_selection",value):
ud = UD_STORE.get_definition(trajConfig["basename"],"axis_selection",value)
......
......@@ -47,7 +47,7 @@ class BasisSelection(IConfigurator):
_default = None
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
......@@ -58,15 +58,13 @@ class BasisSelection(IConfigurator):
keys are the names of three atoms of the molecule that will be used to define respectively the origin, the X and Y axis of the basis
#. str: the axis selection will be performed by reading the corresponding user definition.
:param configuration: the current configuration
:type configuration: MDANSE.Framework.Configurable.Configurable
:param value: the input value
:type value: tuple or str
:note: this configurator depends on 'trajectory' configurator to be configured
'''
trajConfig = configuration[self._dependencies['trajectory']]
trajConfig = self._configurable[self._dependencies['trajectory']]
if UD_STORE.has_definition(trajConfig["basename"],"basis_selection",value):
ud = UD_STORE.get_definition(trajConfig["basename"],"basis_selection",value)
......
......@@ -47,7 +47,7 @@ class BooleanConfigurator(IConfigurator):
_shortCuts = {True : True, "true" : True , "yes" : True, "y" : True, "1" : True, 1 : True,
False : False, "false" : False, "no" : False, "n" : False, "0" : False, 0 : False}
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
......
......@@ -42,7 +42,7 @@ class ComplexNumberConfigurator(IConfigurator):
_default = 0
def __init__(self, name, mini=None, maxi=None, choices=None, **kwargs):
def __init__(self, configurable, name, mini=None, maxi=None, choices=None, **kwargs):
'''
Initializes the configurator.
......@@ -57,7 +57,7 @@ class ComplexNumberConfigurator(IConfigurator):
'''
# The base class constructor.
IConfigurator.__init__(self, name, **kwargs)
IConfigurator.__init__(self, configurable, name, **kwargs)
self._mini = float(mini) if mini is not None else None
......@@ -65,12 +65,10 @@ class ComplexNumberConfigurator(IConfigurator):
self._choices = choices if choices is not None else []
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
:param configuration: the current configuration.
:type configuration: a MDANSE.Framework.Configurable.Configurable object
:param value: the input complex number.
:type value: complex
'''
......
......@@ -41,7 +41,7 @@ class FloatConfigurator(IConfigurator):
_default = 0
def __init__(self, name, mini=None, maxi=None, choices=None, **kwargs):
def __init__(self, configurable, name, mini=None, maxi=None, choices=None, **kwargs):
'''
Initializes the configurator.
......@@ -56,7 +56,7 @@ class FloatConfigurator(IConfigurator):
'''
# The base class constructor.
IConfigurator.__init__(self, name, **kwargs)
IConfigurator.__init__(self, configurable, name, **kwargs)
self._mini = float(mini) if mini is not None else None
......@@ -64,12 +64,10 @@ class FloatConfigurator(IConfigurator):
self._choices = choices if choices is not None else []
def configure(self, configuration, value):
def configure(self, value):
'''
Configure an input value.
:param configuration: the current configuration
:type configuration: a MDANSE.Framework.Configurable.Configurable object
:param value: the input value
:type value: float
'''
......
......@@ -48,7 +48,7 @@ class FramesConfigurator(RangeConfigurator):
type = 'frames'
def __init__(self, name, **kwargs):
def __init__(self, configurable, name, **kwargs):
'''
Initializes the configurator.
......@@ -56,34 +56,30 @@ class FramesConfigurator(RangeConfigurator):
:type name: str
'''
RangeConfigurator.__init__(self, name, sort=True, **kwargs)
RangeConfigurator.__init__(self, configurable, name, sort=True, **kwargs)
def configure(self, configuration, value):
def configure(self, value):
'''
Configure the frames range that will be used to perform an analysis.
:param configuration: the current configuration
:type configuration: a MDANSE.Framework.Configurable.Configurable object
:param value: the input value
:type value: 3-tuple, 'all' or None
'''
trajConfig = configuration[self._dependencies['trajectory']]
trajConfig = self._configurable[self._dependencies['trajectory']]
if value in ["all",None]:
value = (0, trajConfig['length'], 1)
self._mini = -1
self._mini = 0
self._maxi = trajConfig['length']
RangeConfigurator.configure(self, configuration, value)
RangeConfigurator.configure(self, value)
self["n_frames"] = self["number"]
self['time'] = trajConfig['md_time_step']*self['value']
self['relative_time'] = self['time'] - self['time'][0]
# case of single frame selected
try:
self['time_step'] = self['time'][1] - self['time'][0]
......
......@@ -31,6 +31,7 @@ Created on Mar 30, 2015
'''
import collections
import operator
from MDANSE.Framework.Configurators.SingleChoiceConfigurator import SingleChoiceConfigurator
......@@ -61,7 +62,7 @@ class GroupingLevelConfigurator(SingleChoiceConfigurator):
_default = "atom"
def __init__(self, name, choices=None, **kwargs):
def __init__(self, configurable, name, choices=None, **kwargs):
'''
Initializes the configurator.
......@@ -76,7 +77,79 @@ class GroupingLevelConfigurator(SingleChoiceConfigurator):
else:
choices = list(set(LEVELS.keys()).intersection(choices))
SingleChoiceConfigurator.__init__(self, name, choices=choices, **kwargs)
SingleChoiceConfigurator.__init__(self, configurable, name, choices=choices, **kwargs)
def configure(self,value):
'''
:param value: the level of granularity at which the atoms should be grouped
:type value: str
'''
if value is None:
value = "atom"
value = str(value)
SingleChoiceConfigurator.configure(self, value)
if value == "atom":
return
trajConfig = self._configurable[self._dependencies['trajectory']]
atomSelectionConfig = self._configurable[self._dependencies['atom_selection']]
allAtoms = sorted(trajConfig["universe"].atomList(), key = operator.attrgetter('index'))
groups = collections.OrderedDict()
for i in range(atomSelectionConfig["selection_length"]):
idx = atomSelectionConfig["indexes"][i][0]
el = atomSelectionConfig["elements"][i][0]
mass = atomSelectionConfig["masses"][i][0]
at = allAtoms[idx]
lvl = LEVELS[value][at.topLevelChemicalObject().__class__.__name__.lower()]
parent = self.find_parent(at,lvl)
d = groups.setdefault(parent,{})
d.setdefault("indexes",[]).append(idx)
d.setdefault("elements",[]).append(el)
d.setdefault("masses",[]).append(mass)
indexes = []
elements = []
masses = []
names = []
for i,v in enumerate(groups.values()):
names.append("group_%d" % i)
elements.append(v['elements'])
indexes.append(v['indexes'])
masses.append(v['masses'])
atomSelectionConfig["indexes"] = indexes
atomSelectionConfig["elements"] = elements
atomSelectionConfig["masses"] = masses
atomSelectionConfig["names"] = names
atomSelectionConfig["selection_length"] = len(names)
atomSelectionConfig['unique_names'] = sorted(set(atomSelectionConfig['names']))
self["level"] = value
@staticmethod
def find_parent(atom, level):
'''
Retrieve recursively the parent of a given MMTK atom at a given level.
For example, a level of 1 will return the direct parent of the atom.
:note: this is a static method
:param atom: the atom for which the parent is searched for
:type atom: MMTK.Atom object