diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/AxisSelectionConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/AxisSelectionConfigurator.py index d8129e9d45..a9f7168ee7 100644 --- a/MDANSE/Src/MDANSE/Framework/Configurators/AxisSelectionConfigurator.py +++ b/MDANSE/Src/MDANSE/Framework/Configurators/AxisSelectionConfigurator.py @@ -58,10 +58,16 @@ def configure(self, value): self.update(value) e1 = find_atoms_in_molecule( - trajConfig["instance"].universe, self["molecule"], self["endpoint1"], True + trajConfig["instance"]._chemical_system, + self["molecule"], + self["endpoint1"], + True, ) e2 = find_atoms_in_molecule( - trajConfig["instance"].universe, self["molecule"], self["endpoint2"], True + trajConfig["instance"]._chemical_system, + self["molecule"], + self["endpoint2"], + True, ) self["value"] = value diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/HDFInputFileConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/HDFInputFileConfigurator.py index bd11dd23f3..31f8873aff 100644 --- a/MDANSE/Src/MDANSE/Framework/Configurators/HDFInputFileConfigurator.py +++ b/MDANSE/Src/MDANSE/Framework/Configurators/HDFInputFileConfigurator.py @@ -42,6 +42,7 @@ def __init__(self, name, variables=None, **kwargs): InputFileConfigurator.__init__(self, name, **kwargs) self._variables = variables if variables is not None else [] + self._units = {} def configure(self, value): """ @@ -67,6 +68,10 @@ def configure(self, value): for v in self._variables: if v in self["instance"]: self[v] = self["instance"][v][:] + try: + self._units[v] = self["instance"][v].attrs["units"] + except: + self._units[v] = "unitless" else: self.error_status = ( f"the variable {v} was not found in {value} HDF file" @@ -87,7 +92,7 @@ def variables(self): def get_information(self): """ - Returns some basic informations about the contents of theHDF file. + Returns some basic informations about the contents of the HDF file. :return: the informations about the contents of the HDF file. :rtype: str diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/McStasOptionsConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/McStasOptionsConfigurator.py index 4a28d0c6b4..1c098e82f5 100644 --- a/MDANSE/Src/MDANSE/Framework/Configurators/McStasOptionsConfigurator.py +++ b/MDANSE/Src/MDANSE/Framework/Configurators/McStasOptionsConfigurator.py @@ -16,6 +16,7 @@ import os import tempfile import time +from typing import Dict, Any from MDANSE import PLATFORM from MDANSE.Framework.Configurators.IConfigurator import ( @@ -24,6 +25,26 @@ ) +def parse_dictionary(input: str) -> Dict[str, Any]: + big_line = input.strip("\{\}[] \n") + tokens = big_line.split(",") + result = {} + for entry in tokens: + temp = entry.split(":") + key, value = temp[0], ":".join(temp[1:]) + key = key.strip("' ") + value = value.strip(" '") + try: + value = int(value) + except: + try: + value = float(value) + except: + pass + result[key] = value + return result + + class McStasOptionsConfigurator(IConfigurator): """ This configurator allows to input the McStas options that will be used to run a McStas executable file. @@ -50,7 +71,9 @@ def configure(self, value): options = self._default.copy() - for k, v in list(value.items()): + parsed = parse_dictionary(value) + + for k, v in list(parsed.items()): if k not in options: continue options[k] = v diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/McStasParametersConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/McStasParametersConfigurator.py index 3b97a83167..c62b4a19b0 100644 --- a/MDANSE/Src/MDANSE/Framework/Configurators/McStasParametersConfigurator.py +++ b/MDANSE/Src/MDANSE/Framework/Configurators/McStasParametersConfigurator.py @@ -19,6 +19,7 @@ from MDANSE import PLATFORM from MDANSE.Framework.Configurators.IConfigurator import IConfigurator +from MDANSE.Framework.Configurators.McStasOptionsConfigurator import parse_dictionary class McStasParametersConfigurator(IConfigurator): @@ -26,7 +27,7 @@ class McStasParametersConfigurator(IConfigurator): This configurator allows to input the McStas instrument parameters that will be used to run a McStas executable file. """ - _mcStasTypes = {"double": float, "int": int, "StringConfigurator": str} + _mcStasTypes = {"double": float, "int": int, "string": str} _default = { "beam_wavelength_Angs": 2.0, @@ -77,20 +78,27 @@ def configure(self, value): [exePath, "-h"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) + parameters_bytes = s.communicate()[0] + parameters_string = parameters_bytes.decode(encoding="utf-8") + instrParameters = dict( [ (v[0], [v[1], v[2]]) for v in re.findall( - "\s*(\w+)\s*\((\w+)\)\s*\[default='(\S+)'\]", s.communicate()[0] + "\s*(\w+)\s*\((\w+)\)\s*\[default='(\S+)'\]", parameters_string ) if v[0] not in self._exclude ] ) val = {} - for k, v in list(value.items()): + parsed = parse_dictionary(value) + print(f"Parsed input: {parsed}") + print(f"Received from McStas: {instrParameters}") + for k, v in list(parsed.items()): if k not in instrParameters: - instrParameters.pop(k) + # instrParameters.pop(k) # how was that supposed to work? + continue val[k] = self._mcStasTypes[instrParameters[k][0]](v) self["value"] = ["%s=%s" % (k, v) for k, v in list(val.items())] diff --git a/MDANSE/Src/MDANSE/Framework/Formats/MDAFormat.py b/MDANSE/Src/MDANSE/Framework/Formats/MDAFormat.py index d6ac136887..dcc0a8b084 100644 --- a/MDANSE/Src/MDANSE/Framework/Formats/MDAFormat.py +++ b/MDANSE/Src/MDANSE/Framework/Formats/MDAFormat.py @@ -1,5 +1,5 @@ from MDANSE.Framework.Formats.IFormat import IFormat -from MDANSE.Framework.OutputVariables import IOutputVariable +from MDANSE.Framework.OutputVariables.IOutputVariable import IOutputVariable from .HDFFormat import HDFFormat diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/GlobalMotionFilteredTrajectory.py b/MDANSE/Src/MDANSE/Framework/Jobs/GlobalMotionFilteredTrajectory.py index f418b1bc14..88a4ac68b1 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/GlobalMotionFilteredTrajectory.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/GlobalMotionFilteredTrajectory.py @@ -133,7 +133,7 @@ def run_step(self, index): variables = copy.deepcopy(current_configuration.variables) coords = variables.pop("coordinates") current_configuration = RealConfiguration( - trajectory.chemical_system, coords, None, **variables + trajectory.chemical_system, coords, **variables ) trajectory.chemical_system.configuration = current_configuration diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/McStasVirtualInstrument.py b/MDANSE/Src/MDANSE/Framework/Jobs/McStasVirtualInstrument.py index fd9ccd317c..0cccddc791 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/McStasVirtualInstrument.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/McStasVirtualInstrument.py @@ -30,9 +30,10 @@ from MDANSE.Framework.OutputVariables.IOutputVariable import IOutputVariable from MDANSE.Framework.Units import measure from MDANSE.MolecularDynamics.Trajectory import sorted_atoms +from MDANSE.MolecularDynamics.UnitCell import UnitCell MCSTAS_UNITS_LUT = { - "THz": measure(1, "THz", equivalent=True).toval("meV"), + "rad/ps": measure(1, "rad/ps", equivalent=True).toval("meV"), "nm2": measure(1, "nm2").toval("b"), "1/nm": measure(1, "1/nm").toval("1/ang"), } @@ -74,7 +75,7 @@ class McStasVirtualInstrument(IJob): { "widget": "InputFileConfigurator", "label": "MDANSE Coherent Structure Factor", - "variables": ["q", "frequency", "s(q,f)_total"], + "variables": ["q", "omega", "s(q,f)_total"], "default": "dcsf_prot.h5", }, ) @@ -83,11 +84,17 @@ class McStasVirtualInstrument(IJob): { "widget": "InputFileConfigurator", "label": "MDANSE Incoherent Structure Factor", - "variables": ["q", "frequency", "s(q,f)_total"], + "variables": ["q", "omega", "s(q,f)_total"], "default": "disf_prot.h5", }, ) - settings["temperature"] = ("FloatConfigurator", {"default": 298.0}) + settings["temperature"] = ( + "FloatConfigurator", + { + "default": 298.0, + "label": "The sample temperature to be used in the simulation.", + }, + ) settings["display"] = ( "BooleanConfigurator", {"label": "trace the 3D view of the simulation"}, @@ -119,7 +126,8 @@ def initialize(self): self.numberOfSteps = 1 symbols = sorted_atoms( - self.configuration["trajectory"]["instance"].universe, "symbol" + self.configuration["trajectory"]["instance"]._chemical_system.atom_list, + "symbol", ) # Compute some parameters used for a proper McStas run @@ -140,12 +148,10 @@ def initialize(self): * MCSTAS_UNITS_LUT["nm2"] ) for frameIndex in self.configuration["frames"]["value"]: - self.configuration["trajectory"]["instance"].universe.setFromTrajectory( - self.configuration["trajectory"]["instance"], frameIndex + configuration = self.configuration["trajectory"]["instance"].configuration( + frameIndex ) - cellVolume = self.configuration["trajectory"][ - "instance" - ].universe.cellVolume() + cellVolume = configuration._unit_cell.volume self._mcStasPhysicalParameters["density"] += ( self._mcStasPhysicalParameters["weight"] / cellVolume ) @@ -186,8 +192,9 @@ def run_step(self, index): fout.write("# %s\n" % var) data = self.configuration[typ][var][:] + data_unit = self.configuration[typ]._units[var] try: - data *= MCSTAS_UNITS_LUT[self.configuration[typ][var].units] + data *= MCSTAS_UNITS_LUT[data_unit] except KeyError: pass @@ -220,7 +227,7 @@ def run_step(self, index): out, _ = s.communicate() for line in out.splitlines(): - if "ERROR" in line: + if "ERROR" in line.decode(encoding="utf-8"): raise McStasError("An error occured during McStas run: %s" % out) with open( @@ -230,7 +237,7 @@ def run_step(self, index): ), "w", ) as f: - f.write(out) + f.write(out.decode(encoding="utf-8")) return index, None @@ -439,7 +446,7 @@ def read_monitor(self, simFile): Line = Line.split(":") Field = Line[0] Value = "" - Value = string.join(string.join(Line[1 : len(Line)], ":").split("'"), "") + Value = "".join(":".join(Line[1 : len(Line)]).split("'")) strStruct = strStruct + "'" + Field + "':'" + Value + "'" if j < len(Header) - 1: strStruct += "," diff --git a/MDANSE/Tests/UnitTests/test_documentation.py b/MDANSE/Tests/UnitTests/test_documentation.py new file mode 100644 index 0000000000..ce49e6f866 --- /dev/null +++ b/MDANSE/Tests/UnitTests/test_documentation.py @@ -0,0 +1,14 @@ + +import pytest + +from MDANSE.Framework.Jobs.IJob import IJob + + +job_list = IJob.indirect_subclasses() + + +@pytest.mark.parametrize("job_name", job_list) +def test_documentation_building(job_name): + instance = IJob.create(job_name) + docs = instance.build_doc() + assert len(docs) > 0 diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/JobTree.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/JobTree.py index f93635cb0a..51ca358390 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/JobTree.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/JobTree.py @@ -65,6 +65,12 @@ def createNode(self, name: str, thing, filter: str = ""): self._nodes[new_number] = new_node self._values[new_number] = thing self._docstrings[new_number] = thing.__doc__ + try: + self._docstrings[new_number] += "\n" + thing.build_doc() + except AttributeError: + pass + except TypeError: + pass if hasattr(thing, "category"): if filter: if filter in thing.category: