From fae44c12a5f8240b3f1d5bfefb44f6977a576735 Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Thu, 5 Dec 2024 11:04:02 +0000 Subject: [PATCH 1/7] Check input weights in NDTSF --- .../NeutronDynamicTotalStructureFactor.py | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py index 6b65f337c..068740525 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py @@ -18,6 +18,7 @@ import numpy as np +from MDANSE.MLogging import LOG from MDANSE.Chemistry import ATOMS_DATABASE from MDANSE.Core.Error import Error from MDANSE.Framework.Jobs.IJob import IJob @@ -47,11 +48,11 @@ class NeutronDynamicTotalStructureFactor(IJob): settings["trajectory"] = ("HDFTrajectoryConfigurator", {}) settings["dcsf_input_file"] = ( "HDFInputFileConfigurator", - {"label": "MDANSE Coherent Structure Factor", "default": "dcsf.h5"}, + {"label": "MDANSE Coherent Structure Factor", "default": "dcsf.mda"}, ) settings["disf_input_file"] = ( "HDFInputFileConfigurator", - {"label": "MDANSE Incoherent Structure Factor", "default": "disf.h5"}, + {"label": "MDANSE Incoherent Structure Factor", "default": "disf.mda"}, ) settings["atom_selection"] = ( "AtomSelectionConfigurator", @@ -354,6 +355,20 @@ def initialize(self): units="nm2/ps", main_result=True, ) + self._input_disf_weight = ( + self.configuration["disf_input_file"]["instance"][ + "metadata/inputs/weights" + ][0] + .decode() + .strip('"') + ) + self._input_dcsf_weight = ( + self.configuration["dcsf_input_file"]["instance"][ + "metadata/inputs/weights" + ][0] + .decode() + .strip('"') + ) def run_step(self, index): """ @@ -390,24 +405,20 @@ def finalize(self): # Compute coherent functions and structure factor for pair in self._elementsPairs: - bi = ATOMS_DATABASE.get_atom_property(pair[0], "b_coherent") - bj = ATOMS_DATABASE.get_atom_property(pair[1], "b_coherent") - ni = nAtomsPerElement[pair[0]] - nj = nAtomsPerElement[pair[1]] - ci = ni / nTotalAtoms - cj = nj / nTotalAtoms + if self._input_dcsf_weight == "equal": + bi = ATOMS_DATABASE.get_atom_property(pair[0], "b_coherent") + bj = ATOMS_DATABASE.get_atom_property(pair[1], "b_coherent") + elif self._input_dcsf_weight == "b_coherent": + bi = bj = 1.0 + else: + LOG.error("Input DCSF weights should be b_coherent or equal") + return self._outputData["f(q,t)_coh_weighted_%s%s" % pair][:] = ( - self._outputData["f(q,t)_coh_%s%s" % pair][:] - * np.sqrt(ci * cj) - * bi - * bj + self._outputData["f(q,t)_coh_%s%s" % pair][:] * bi * bj ) self._outputData["s(q,f)_coh_weighted_%s%s" % pair][:] = ( - self._outputData["s(q,f)_coh_%s%s" % pair][:] - * np.sqrt(ci * cj) - * bi - * bj + self._outputData["s(q,f)_coh_%s%s" % pair][:] * bi * bj ) if pair[0] == pair[1]: # Add a factor 2 if the two elements are different self._outputData["f(q,t)_coh_total"][:] += self._outputData[ @@ -425,16 +436,20 @@ def finalize(self): ) # Compute incoherent functions and structure factor - for element, ni in nAtomsPerElement.items(): - bi = ATOMS_DATABASE.get_atom_property(element, "b_incoherent2") - ni = nAtomsPerElement[element] - ci = ni / nTotalAtoms + for element, _ in nAtomsPerElement.items(): + if self._input_dcsf_weight == "equal": + bi = ATOMS_DATABASE.get_atom_property(element, "b_incoherent2") + elif self._input_dcsf_weight == "b_incoherent2": + bi = 1.0 + else: + LOG.error("Input DCSF weights should be b_incoherent2 or equal") + return self._outputData["f(q,t)_inc_weighted_%s" % element][:] = ( - self._outputData["f(q,t)_inc_%s" % element][:] * ci * bi + self._outputData["f(q,t)_inc_%s" % element][:] * bi ) self._outputData["s(q,f)_inc_weighted_%s" % element][:] = ( - self._outputData["s(q,f)_inc_%s" % element][:] * ci * bi + self._outputData["s(q,f)_inc_%s" % element][:] * bi ) self._outputData["f(q,t)_inc_total"][:] += self._outputData[ From 313e456a6c7f59bb34d02fda79730b583c5c2586 Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Thu, 5 Dec 2024 12:55:40 +0000 Subject: [PATCH 2/7] Correct weight checking in NDTSF --- .../Framework/Jobs/NeutronDynamicTotalStructureFactor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py index 068740525..d953b6148 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py @@ -33,7 +33,7 @@ class NeutronDynamicTotalStructureFactor(IJob): Computes the dynamic total structure factor for a set of atoms as the sum of the incoherent and coherent structure factors """ - enabled = False + enabled = True label = "Neutron Dynamic Total Structure Factor" @@ -437,9 +437,9 @@ def finalize(self): # Compute incoherent functions and structure factor for element, _ in nAtomsPerElement.items(): - if self._input_dcsf_weight == "equal": + if self._input_disf_weight == "equal": bi = ATOMS_DATABASE.get_atom_property(element, "b_incoherent2") - elif self._input_dcsf_weight == "b_incoherent2": + elif self._input_disf_weight == "b_incoherent2": bi = 1.0 else: LOG.error("Input DCSF weights should be b_incoherent2 or equal") From 5a2a9bc50290754138609055db29f064f57b234e Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Fri, 13 Dec 2024 17:04:05 +0000 Subject: [PATCH 3/7] Add documentation to Arithmetic.py --- .../Configurators/WeightsConfigurator.py | 22 +++--- MDANSE/Src/MDANSE/Mathematics/Arithmetic.py | 70 ++++++++++++++++--- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/MDANSE/Src/MDANSE/Framework/Configurators/WeightsConfigurator.py b/MDANSE/Src/MDANSE/Framework/Configurators/WeightsConfigurator.py index 370be33cd..b0d73ca4d 100644 --- a/MDANSE/Src/MDANSE/Framework/Configurators/WeightsConfigurator.py +++ b/MDANSE/Src/MDANSE/Framework/Configurators/WeightsConfigurator.py @@ -106,20 +106,24 @@ def configure(self, value): self.error_status = "OK" def get_weights(self): - ascfg = self._configurable[self._dependencies["atom_selection"]] + atom_selection_configurator = self._configurable[ + self._dependencies["atom_selection"] + ] weights = {} - for i in range(ascfg["selection_length"]): - name = ascfg["names"][i] - for el in ascfg["elements"][i]: - p = ATOMS_DATABASE.get_atom_property(el, self["property"]) + for i in range(atom_selection_configurator["selection_length"]): + name = atom_selection_configurator["names"][i] + for element in atom_selection_configurator["elements"][i]: + property = ATOMS_DATABASE.get_atom_property(element, self["property"]) if name in weights: - weights[name] += p + weights[name] += property else: - weights[name] = p + weights[name] = property - for k, v in list(ascfg.get_natoms().items()): - weights[k] /= v + for element, num_atoms in list( + atom_selection_configurator.get_natoms().items() + ): + weights[element] /= num_atoms return weights diff --git a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py index fa08a203e..585e0135e 100644 --- a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py +++ b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py @@ -13,29 +13,49 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +from typing import List, Dict, Tuple import itertools import numpy as np -def get_weights(props, contents, dim): +def get_weights(props: Dict[str, float], contents: Dict[str, int], dim: int): + """Calculates the scaling factor to be applied to output datasets + of an analysis. + + Parameters + ---------- + props : Dict[str, float] + Dictionary of values of an atom property for a selected object, averaged over atoms in that object + contents : Dict[str, int] + Dictionary of numbers of atoms in an object + dim : int + number of atom types in the label of the output datasets (e.g. 1 for "O", 2 for "CuCu") + + Returns + ------- + Tuple(Dict[Tuple[str], float], float) + Dictionary of scaling factors per dataset key, and a sum of all the factors + """ normFactor = None weights = {} cartesianProduct = set(itertools.product(list(props.keys()), repeat=dim)) for elements in cartesianProduct: - n = np.prod([contents[el] for el in elements]) - p = np.prod(np.array([props[el] for el in elements]), axis=0) + atom_number_product = np.prod([contents[el] for el in elements]) + property_product = np.prod(np.array([props[el] for el in elements]), axis=0) - fact = n * p + factor = atom_number_product * property_product + # E.g. for property b_coh, 5 Cu atoms and dim=2 + # factor = 5*5 * b_coh(Cu)*b_coh(Cu) - weights[elements] = np.float64(np.copy(fact)) + weights[elements] = np.float64(np.copy(factor)) if normFactor is None: - normFactor = fact + normFactor = factor else: - normFactor += fact + normFactor += factor if abs(normFactor) > 0.0: # if normFactor is 0, all weights are 0 too. for k in list(weights.keys()): @@ -44,8 +64,40 @@ def get_weights(props, contents, dim): return weights, normFactor -def weight(props, values, contents, dim, key, symmetric=True, update_partials=False): - weights = get_weights(props, contents, dim)[0] +def weight( + props: Dict[str, float], + values: Dict[str, np.ndarray], + contents: Dict[str, int], + dim: int, + key: str, + symmetric: bool = True, + update_partials: bool = False, +): + """_summary_ + + Parameters + ---------- + props : Dict[str, float] + Dictionary of values of an atom property for a selected object, averaged over atoms in that object + values : Dict[str, np.ndarray] + Dictionary of data arrays containing analysis results. + contents : Dict[str, int] + Dictionary of numbers of atoms in an object + dim : int + number of atom types in the label of the output datasets (e.g. 1 for "O", 2 for "CuCu") + key : str + A string data set name with formatting elements (placeholders for chemical element labels) + symmetric : bool, optional + do not generate results for the same elements in a different sequence, by default True + update_partials : bool, optional + Partial results will be rescaled if this is true, by default False + + Returns + ------- + np.ndarray + total sum of all the component arrays scaled by their weights + """ + weights, _ = get_weights(props, contents, dim) weightedSum = None matches = dict([(key % k, k) for k in list(weights.keys())]) From 38f62fa7c337588dd0e7177d478e5a978d546ad2 Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Mon, 16 Dec 2024 11:47:45 +0000 Subject: [PATCH 4/7] Move get_weights outside of the weight function --- .../Jobs/CurrentCorrelationFunction.py | 20 +++++++------------ .../MDANSE/Framework/Jobs/DensityOfStates.py | 11 ++++------ .../MDANSE/Framework/Jobs/DensityProfile.py | 8 ++++---- .../Jobs/DynamicCoherentStructureFactor.py | 13 +++++------- .../Jobs/DynamicIncoherentStructureFactor.py | 12 ++++------- .../Jobs/ElasticIncoherentStructureFactor.py | 7 +++---- ...aussianDynamicIncoherentStructureFactor.py | 12 ++++------- .../Jobs/GeneralAutoCorrelationFunction.py | 5 +++-- .../Framework/Jobs/MeanSquareDisplacement.py | 5 +++-- .../Jobs/PairDistributionFunction.py | 8 +++----- .../Jobs/PositionAutoCorrelationFunction.py | 5 +++-- .../Framework/Jobs/PositionPowerSpectrum.py | 11 ++++------ .../Framework/Jobs/StaticStructureFactor.py | 12 ++++------- .../Framework/Jobs/VanHoveFunctionDistinct.py | 7 +++---- .../Framework/Jobs/VanHoveFunctionSelf.py | 11 ++++------ .../Jobs/VelocityAutoCorrelationFunction.py | 6 +++--- .../Jobs/XRayStaticStructureFactor.py | 12 ++++------- MDANSE/Src/MDANSE/Mathematics/Arithmetic.py | 20 ++++++++----------- 18 files changed, 73 insertions(+), 112 deletions(-) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py index c30e898a5..289fcf1ba 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py @@ -21,7 +21,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import ( differentiate, get_spectrum, @@ -391,36 +391,30 @@ def finalize(self): fft="rfft", ) + weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 2) jqtLongTotal = weight( - self.configuration["weights"].get_weights(), self._outputData, - nAtomsPerElement, - 2, + weight_dict, "j(q,t)_long_%s%s", ) self._outputData["j(q,t)_long_total"][:] = jqtLongTotal jqtTransTotal = weight( - self.configuration["weights"].get_weights(), self._outputData, - nAtomsPerElement, - 2, + weight_dict, "j(q,t)_trans_%s%s", ) self._outputData["j(q,t)_trans_total"][:] = jqtTransTotal sqfLongTotal = weight( - self.configuration["weights"].get_weights(), self._outputData, - nAtomsPerElement, - 2, + weight_dict, "J(q,f)_long_%s%s", ) self._outputData["J(q,f)_long_total"][:] = sqfLongTotal sqfTransTotal = weight( - self.configuration["weights"].get_weights(), self._outputData, - nAtomsPerElement, - 2, + weight_dict, "J(q,f)_trans_%s%s", ) self._outputData["J(q,f)_trans_total"][:] = sqfTransTotal diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py b/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py index d9f4c62aa..5c1654527 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py @@ -18,7 +18,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import differentiate, get_spectrum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms from MDANSE.MLogging import LOG @@ -238,19 +238,16 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 1) self._outputData["vacf_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "vacf_%s", update_partials=True, ) self._outputData["dos_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "dos_%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py b/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py index a6f2b51d7..d112d0d3e 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py @@ -21,7 +21,7 @@ from MDANSE.Core.Error import Error from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights class DensityProfileError(Error): @@ -176,11 +176,11 @@ def finalize(self): for element in n_atoms_per_element.keys(): self._outputData["dp_%s" % element] += self.numberOfSteps + weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, n_atoms_per_element, 1) dp_total = weight( - self.configuration["weights"].get_weights(), self._outputData, - n_atoms_per_element, - 1, + weight_dict, "dp_%s", ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py index 818522b32..1fd3f8cd6 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py @@ -22,7 +22,7 @@ from MDANSE.Core.Error import Error from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import get_spectrum @@ -259,21 +259,18 @@ def finalize(self): self.configuration["instrument_resolution"]["time_step"], axis=1, ) - + weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 2) self._outputData["f(q,t)_total"][:] = weight( - self.configuration["weights"].get_weights(), self._outputData, - nAtomsPerElement, - 2, + weight_dict, "f(q,t)_%s%s", update_partials=True, ) self._outputData["s(q,f)_total"][:] = weight( - self.configuration["weights"].get_weights(), self._outputData, - nAtomsPerElement, - 2, + weight_dict, "s(q,f)_%s%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py index 63e937560..0913c06c3 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py @@ -20,7 +20,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import get_spectrum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -265,21 +265,17 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() - + weight_dict = get_weights(weights, nAtomsPerElement, 1) self._outputData["f(q,t)_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "f(q,t)_%s", update_partials=True, ) self._outputData["s(q,f)_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "s(q,f)_%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py index ef1c022a7..c65b3c383 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py @@ -19,7 +19,7 @@ import numpy as np from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -198,11 +198,10 @@ def finalize(self): self._outputData["eisf_%s" % element][:] /= number weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 1) self._outputData["eisf_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "eisf_%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py index 8b2f9b712..12be148f5 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py @@ -19,7 +19,7 @@ import numpy as np from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import get_spectrum from MDANSE.MolecularDynamics.Analysis import mean_square_displacement from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -250,21 +250,17 @@ def finalize(self): axis=1, ) weights = self.configuration["weights"].get_weights() - + weight_dict = get_weights(weights, nAtomsPerElement, 1) self._outputData["f(q,t)_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "f(q,t)_%s", update_partials=True, ) self._outputData["s(q,f)_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "s(q,f)_%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py index b13a50091..747c9adba 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py @@ -17,7 +17,7 @@ import collections from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import correlation, normalize @@ -168,7 +168,8 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() - gacfTotal = weight(weights, self._outputData, nAtomsPerElement, 1, "gacf_%s") + weight_dict = get_weights(weights, nAtomsPerElement, 1) + gacfTotal = weight(self._outputData, weight_dict, "gacf_%s") self._outputData["gacf_total"][:] = gacfTotal diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py b/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py index 89f2ffac2..33e4da018 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py @@ -18,7 +18,7 @@ from MDANSE.MolecularDynamics.Analysis import mean_square_displacement from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -196,7 +196,8 @@ def finalize(self): self._outputData["msd_%s" % element] /= number weights = self.configuration["weights"].get_weights() - msdTotal = weight(weights, self._outputData, nAtomsPerElement, 1, "msd_%s") + weight_dict = get_weights(weights, nAtomsPerElement, 1) + msdTotal = weight(self._outputData, weight_dict, "msd_%s") self._outputData.add( "msd_total", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py index cb9669905..c3fa38ae4 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py @@ -17,7 +17,7 @@ import numpy as np from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights class PairDistributionFunction(DistanceHistogram): @@ -149,13 +149,11 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() - + weight_dict = get_weights(weights, nAtomsPerElement, 2) for i in ["_intra", "_inter", ""]: pdf = weight( - weights, self._outputData, - nAtomsPerElement, - 2, + weight_dict, "pdf{}_%s%s".format(i if i else "_total"), ) self._outputData["pdf%s_total" % i][:] = pdf diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py index 5b40c2add..b608f013c 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py @@ -19,7 +19,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import normalize from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -180,7 +180,8 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() - pacfTotal = weight(weights, self._outputData, nAtomsPerElement, 1, "pacf_%s") + weight_dict = get_weights(weights, nAtomsPerElement, 1) + pacfTotal = weight(self._outputData, weight_dict, "pacf_%s") self._outputData.add( "pacf_total", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py index 9ebc6d34c..75b96b512 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py @@ -19,7 +19,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import differentiate, get_spectrum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms from MDANSE.MLogging import LOG @@ -219,19 +219,16 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 1) self._outputData["pacf_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "pacf_%s", update_partials=True, ) self._outputData["pps_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "pps_%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py index 5e20929d7..5aab05448 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py @@ -19,7 +19,7 @@ import numpy as np from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights class StaticStructureFactor(DistanceHistogram): @@ -207,15 +207,11 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() - - ssfIntra = weight( - weights, self._outputData, nAtomsPerElement, 2, "ssf_intra_%s%s" - ) + weight_dict = get_weights(weights, nAtomsPerElement, 2) + ssfIntra = weight(self._outputData, weight_dict, "ssf_intra_%s%s") self._outputData["ssf_intra"][:] = ssfIntra - ssfInter = weight( - weights, self._outputData, nAtomsPerElement, 2, "ssf_inter_%s%s" - ) + ssfInter = weight(self._outputData, weight_dict, "ssf_inter_%s%s") self._outputData["ssf_inter"][:] = ssfInter diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py index 4cdad36be..4172a67e3 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py @@ -21,7 +21,7 @@ from MDANSE.Extensions import van_hove from MDANSE.Framework.Jobs.IJob import IJob, JobError from MDANSE.MolecularDynamics.TrajectoryUtils import atom_index_to_molecule_index -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights class VanHoveFunctionDistinct(IJob): @@ -319,12 +319,11 @@ def finalize(self): ] = van_hove weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 2) for i in ["_intra", "_inter", ""]: pdf = weight( - weights, self._outputData, - nAtomsPerElement, - 2, + weight_dict, "g(r,t){}_%s%s".format(i if i else "_total"), ) self._outputData["g(r,t)%s_total" % i][...] = pdf diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py index 056c78b9c..f1d3d753c 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py @@ -19,7 +19,7 @@ from MDANSE.Extensions import van_hove from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights class VanHoveFunctionSelf(IJob): @@ -243,19 +243,16 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 1) self._outputData["g(r,t)_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "g(r,t)_%s", update_partials=True, ) self._outputData["4_pi_r2_g(r,t)_total"][:] = weight( - weights, self._outputData, - nAtomsPerElement, - 1, + weight_dict, "4_pi_r2_g(r,t)_%s", update_partials=True, ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py index 55c96ed2f..dd3247ec2 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py @@ -18,7 +18,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights from MDANSE.Mathematics.Signal import differentiate, normalize from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -210,8 +210,8 @@ def finalize(self): self._outputData["vacf_%s" % element] /= number weights = self.configuration["weights"].get_weights() - - vacfTotal = weight(weights, self._outputData, nAtomsPerElement, 1, "vacf_%s") + weight_dict = get_weights(weights, nAtomsPerElement, 1) + vacfTotal = weight(self._outputData, weight_dict, "vacf_%s") self._outputData["vacf_total"][:] = vacfTotal if self.configuration["normalize"]["value"]: diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py index 254f492f1..1b23c0bb7 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py @@ -20,7 +20,7 @@ from MDANSE.Chemistry import ATOMS_DATABASE from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram -from MDANSE.Mathematics.Arithmetic import weight +from MDANSE.Mathematics.Arithmetic import weight, get_weights def atomic_scattering_factor(element, qvalues): @@ -195,15 +195,11 @@ def finalize(self): (k, atomic_scattering_factor(k, self._outputData["q"])) for k in list(nAtomsPerElement.keys()) ) - - xssfIntra = weight( - asf, self._outputData, nAtomsPerElement, 2, "xssf_intra_%s%s" - ) + weight_dict = get_weights(asf, nAtomsPerElement, 2) + xssfIntra = weight(self._outputData, weight_dict, "xssf_intra_%s%s") self._outputData["xssf_intra"][:] = xssfIntra - xssfInter = weight( - asf, self._outputData, nAtomsPerElement, 2, "xssf_inter_%s%s" - ) + xssfInter = weight(self._outputData, weight_dict, "xssf_inter_%s%s") self._outputData["xssf_inter"][:] = xssfInter self._outputData["xssf_total"][:] = xssfIntra + xssfInter diff --git a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py index 585e0135e..7e3a6173e 100644 --- a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py +++ b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py @@ -61,14 +61,14 @@ def get_weights(props: Dict[str, float], contents: Dict[str, int], dim: int): for k in list(weights.keys()): weights[k] /= np.float64(normFactor) - return weights, normFactor + weights["sum"] = normFactor + + return weights def weight( - props: Dict[str, float], values: Dict[str, np.ndarray], - contents: Dict[str, int], - dim: int, + weights: Dict[str, float], key: str, symmetric: bool = True, update_partials: bool = False, @@ -77,14 +77,10 @@ def weight( Parameters ---------- - props : Dict[str, float] - Dictionary of values of an atom property for a selected object, averaged over atoms in that object values : Dict[str, np.ndarray] Dictionary of data arrays containing analysis results. - contents : Dict[str, int] - Dictionary of numbers of atoms in an object - dim : int - number of atom types in the label of the output datasets (e.g. 1 for "O", 2 for "CuCu") + weights : Dict[str, float] + Dictionary of scaling factors per dataset key : str A string data set name with formatting elements (placeholders for chemical element labels) symmetric : bool, optional @@ -97,9 +93,9 @@ def weight( np.ndarray total sum of all the component arrays scaled by their weights """ - weights, _ = get_weights(props, contents, dim) weightedSum = None - matches = dict([(key % k, k) for k in list(weights.keys())]) + matches = dict([(key % k, k) for k in list(weights.keys()) if k not in ["sum"]]) + dim = key.count("%s") for k, val in values.items(): if k not in matches: From 60f0ec893374298b5ca10013b69529f1429a5b31 Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Mon, 16 Dec 2024 16:34:06 +0000 Subject: [PATCH 5/7] Write unscaled partials with scaling_factor as attribute --- MDANSE/Src/MDANSE/Core/Platform.py | 4 +- MDANSE/Src/MDANSE/Core/Singleton.py | 2 +- .../Jobs/CurrentCorrelationFunction.py | 14 +++-- .../MDANSE/Framework/Jobs/DensityOfStates.py | 8 +-- .../MDANSE/Framework/Jobs/DensityProfile.py | 5 +- .../Jobs/DynamicCoherentStructureFactor.py | 8 +-- .../Jobs/DynamicIncoherentStructureFactor.py | 8 +-- .../Jobs/ElasticIncoherentStructureFactor.py | 5 +- ...aussianDynamicIncoherentStructureFactor.py | 8 +-- .../Jobs/GeneralAutoCorrelationFunction.py | 7 +-- .../Framework/Jobs/MeanSquareDisplacement.py | 5 +- .../Jobs/PairDistributionFunction.py | 7 ++- .../Jobs/PositionAutoCorrelationFunction.py | 7 +-- .../Framework/Jobs/PositionPowerSpectrum.py | 8 +-- .../Framework/Jobs/StaticStructureFactor.py | 8 +-- .../Framework/Jobs/VanHoveFunctionDistinct.py | 9 +++- .../Framework/Jobs/VanHoveFunctionSelf.py | 8 +-- .../Jobs/VelocityAutoCorrelationFunction.py | 9 ++-- .../Jobs/XRayStaticStructureFactor.py | 8 +-- .../OutputVariables/IOutputVariable.py | 4 +- MDANSE/Src/MDANSE/Mathematics/Arithmetic.py | 51 ++++++++++++++++--- .../MDANSE_GUI/Tabs/Models/PlottingContext.py | 39 ++++++++++++-- .../Src/MDANSE_GUI/Tabs/Plotters/Single.py | 2 +- .../Src/MDANSE_GUI/Tabs/Plotters/Text.py | 10 ++-- 24 files changed, 172 insertions(+), 72 deletions(-) diff --git a/MDANSE/Src/MDANSE/Core/Platform.py b/MDANSE/Src/MDANSE/Core/Platform.py index 4feaec691..561f6349c 100644 --- a/MDANSE/Src/MDANSE/Core/Platform.py +++ b/MDANSE/Src/MDANSE/Core/Platform.py @@ -45,11 +45,11 @@ def __new__(cls, *args, **kwargs): """ Create a new instance of Platform class. - :param cls: the class to instanciate. + :param cls: the class to instantiate. :type cls: class """ - # Case of the first instanciation. + # Case of the first instantiation. if cls.__instance is None: cls.__instance = super(Platform, cls).__new__(cls, *args, **kwargs) diff --git a/MDANSE/Src/MDANSE/Core/Singleton.py b/MDANSE/Src/MDANSE/Core/Singleton.py index 01154c5a5..7ac2905a9 100644 --- a/MDANSE/Src/MDANSE/Core/Singleton.py +++ b/MDANSE/Src/MDANSE/Core/Singleton.py @@ -24,7 +24,7 @@ class Singleton(type): def __call__(self, *args, **kwargs): """ - Creates (or returns if it has already been instanciated) an instance of the class. + Creates (or returns if it has already been instantiated) an instance of the class. """ if self.__name__ not in self.__instances: diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py index 289fcf1ba..6856211ce 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/CurrentCorrelationFunction.py @@ -21,7 +21,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import ( differentiate, get_spectrum, @@ -393,26 +393,30 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 2) - jqtLongTotal = weight( + assign_weights(self._outputData, weight_dict, "j(q,t)_long_%s%s") + assign_weights(self._outputData, weight_dict, "j(q,t)_trans_%s%s") + assign_weights(self._outputData, weight_dict, "J(q,f)_long_%s%s") + assign_weights(self._outputData, weight_dict, "J(q,f)_trans_%s%s") + jqtLongTotal = weighted_sum( self._outputData, weight_dict, "j(q,t)_long_%s%s", ) self._outputData["j(q,t)_long_total"][:] = jqtLongTotal - jqtTransTotal = weight( + jqtTransTotal = weighted_sum( self._outputData, weight_dict, "j(q,t)_trans_%s%s", ) self._outputData["j(q,t)_trans_total"][:] = jqtTransTotal - sqfLongTotal = weight( + sqfLongTotal = weighted_sum( self._outputData, weight_dict, "J(q,f)_long_%s%s", ) self._outputData["J(q,f)_long_total"][:] = sqfLongTotal - sqfTransTotal = weight( + sqfTransTotal = weighted_sum( self._outputData, weight_dict, "J(q,f)_trans_%s%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py b/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py index 5c1654527..42c2c1c4a 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py @@ -18,7 +18,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import differentiate, get_spectrum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms from MDANSE.MLogging import LOG @@ -239,13 +239,15 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - self._outputData["vacf_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "vacf_%s") + assign_weights(self._outputData, weight_dict, "dos_%s") + self._outputData["vacf_total"][:] = weighted_sum( self._outputData, weight_dict, "vacf_%s", update_partials=True, ) - self._outputData["dos_total"][:] = weight( + self._outputData["dos_total"][:] = weighted_sum( self._outputData, weight_dict, "dos_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py b/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py index d112d0d3e..fd8be4851 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DensityProfile.py @@ -21,7 +21,7 @@ from MDANSE.Core.Error import Error from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum class DensityProfileError(Error): @@ -178,7 +178,8 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, n_atoms_per_element, 1) - dp_total = weight( + assign_weights(self._outputData, weight_dict, "dp_%s") + dp_total = weighted_sum( self._outputData, weight_dict, "dp_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py index 1fd3f8cd6..b2dc3271c 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py @@ -22,7 +22,7 @@ from MDANSE.Core.Error import Error from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import get_spectrum @@ -261,14 +261,16 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 2) - self._outputData["f(q,t)_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "f(q,t)_%s%s") + assign_weights(self._outputData, weight_dict, "s(q,f)_%s%s") + self._outputData["f(q,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "f(q,t)_%s%s", update_partials=True, ) - self._outputData["s(q,f)_total"][:] = weight( + self._outputData["s(q,f)_total"][:] = weighted_sum( self._outputData, weight_dict, "s(q,f)_%s%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py index 0913c06c3..6d1a3c62b 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py @@ -20,7 +20,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import get_spectrum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -266,14 +266,16 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - self._outputData["f(q,t)_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "f(q,t)_%s") + assign_weights(self._outputData, weight_dict, "s(q,f)_%s") + self._outputData["f(q,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "f(q,t)_%s", update_partials=True, ) - self._outputData["s(q,f)_total"][:] = weight( + self._outputData["s(q,f)_total"][:] = weighted_sum( self._outputData, weight_dict, "s(q,f)_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py index c65b3c383..c7a3f44af 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py @@ -19,7 +19,7 @@ import numpy as np from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -199,7 +199,8 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - self._outputData["eisf_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "eisf_%s") + self._outputData["eisf_total"][:] = weighted_sum( self._outputData, weight_dict, "eisf_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py index 12be148f5..974761553 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py @@ -19,7 +19,7 @@ import numpy as np from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import get_spectrum from MDANSE.MolecularDynamics.Analysis import mean_square_displacement from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -251,14 +251,16 @@ def finalize(self): ) weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - self._outputData["f(q,t)_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "f(q,t)_%s") + assign_weights(self._outputData, weight_dict, "s(q,f)_%s") + self._outputData["f(q,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "f(q,t)_%s", update_partials=True, ) - self._outputData["s(q,f)_total"][:] = weight( + self._outputData["s(q,f)_total"][:] = weighted_sum( self._outputData, weight_dict, "s(q,f)_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py index 747c9adba..06ad91ff3 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/GeneralAutoCorrelationFunction.py @@ -17,7 +17,7 @@ import collections from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import correlation, normalize @@ -163,13 +163,14 @@ def finalize(self): if self._outputData["gacf_{}}".format(element)][0] == 0: raise ValueError("The normalization factor is equal to zero") else: - self._outputData["gacf_{}".format(element)] = normalize( + self._outputData["gacf_{}".format(element)][:] = normalize( self._outputData["gacf_%s" % element], axis=0 ) weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - gacfTotal = weight(self._outputData, weight_dict, "gacf_%s") + assign_weights(self._outputData, weight_dict, "gacf_%s") + gacfTotal = weighted_sum(self._outputData, weight_dict, "gacf_%s") self._outputData["gacf_total"][:] = gacfTotal diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py b/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py index 33e4da018..425a1b988 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/MeanSquareDisplacement.py @@ -18,7 +18,7 @@ from MDANSE.MolecularDynamics.Analysis import mean_square_displacement from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -197,7 +197,8 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - msdTotal = weight(self._outputData, weight_dict, "msd_%s") + assign_weights(self._outputData, weight_dict, "msd_%s") + msdTotal = weighted_sum(self._outputData, weight_dict, "msd_%s") self._outputData.add( "msd_total", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py index c3fa38ae4..74addcd76 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py @@ -17,7 +17,7 @@ import numpy as np from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum class PairDistributionFunction(DistanceHistogram): @@ -151,7 +151,10 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 2) for i in ["_intra", "_inter", ""]: - pdf = weight( + assign_weights( + self._outputData, weight_dict, "pdf{}_%s%s".format(i if i else "_total") + ) + pdf = weighted_sum( self._outputData, weight_dict, "pdf{}_%s%s".format(i if i else "_total"), diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py index b608f013c..9b315a7da 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py @@ -19,7 +19,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import normalize from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -175,13 +175,14 @@ def finalize(self): if self._outputData["pacf_%s" % element][0] == 0: raise ValueError("The normalization factor is equal to zero !!!") else: - self._outputData["pacf_%s" % element] = normalize( + self._outputData["pacf_%s" % element][:] = normalize( self._outputData["pacf_%s" % element], axis=0 ) weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - pacfTotal = weight(self._outputData, weight_dict, "pacf_%s") + assign_weights(self._outputData, weight_dict, "pacf_%s") + pacfTotal = weighted_sum(self._outputData, weight_dict, "pacf_%s") self._outputData.add( "pacf_total", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py index 75b96b512..6041a64b2 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py @@ -19,7 +19,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import differentiate, get_spectrum from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms from MDANSE.MLogging import LOG @@ -220,13 +220,15 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - self._outputData["pacf_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "pacf_%s") + assign_weights(self._outputData, weight_dict, "pps_%s") + self._outputData["pacf_total"][:] = weighted_sum( self._outputData, weight_dict, "pacf_%s", update_partials=True, ) - self._outputData["pps_total"][:] = weight( + self._outputData["pps_total"][:] = weighted_sum( self._outputData, weight_dict, "pps_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py index 5aab05448..cada0ed6c 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py @@ -19,7 +19,7 @@ import numpy as np from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum class StaticStructureFactor(DistanceHistogram): @@ -208,10 +208,12 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 2) - ssfIntra = weight(self._outputData, weight_dict, "ssf_intra_%s%s") + assign_weights(self._outputData, weight_dict, "ssf_intra_%s%s") + assign_weights(self._outputData, weight_dict, "ssf_inter_%s%s") + ssfIntra = weighted_sum(self._outputData, weight_dict, "ssf_intra_%s%s") self._outputData["ssf_intra"][:] = ssfIntra - ssfInter = weight(self._outputData, weight_dict, "ssf_inter_%s%s") + ssfInter = weighted_sum(self._outputData, weight_dict, "ssf_inter_%s%s") self._outputData["ssf_inter"][:] = ssfInter diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py index 4172a67e3..ab7e7c4a7 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py @@ -21,7 +21,7 @@ from MDANSE.Extensions import van_hove from MDANSE.Framework.Jobs.IJob import IJob, JobError from MDANSE.MolecularDynamics.TrajectoryUtils import atom_index_to_molecule_index -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum class VanHoveFunctionDistinct(IJob): @@ -321,7 +321,12 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 2) for i in ["_intra", "_inter", ""]: - pdf = weight( + assign_weights( + self._outputData, + weight_dict, + "g(r,t){}_%s%s".format(i if i else "_total"), + ) + pdf = weighted_sum( self._outputData, weight_dict, "g(r,t){}_%s%s".format(i if i else "_total"), diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py index f1d3d753c..7aa5ce20e 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py @@ -19,7 +19,7 @@ from MDANSE.Extensions import van_hove from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum class VanHoveFunctionSelf(IJob): @@ -244,13 +244,15 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - self._outputData["g(r,t)_total"][:] = weight( + assign_weights(self._outputData, weight_dict, "g(r,t)_%s") + assign_weights(self._outputData, weight_dict, "4_pi_r2_g(r,t)_%s") + self._outputData["g(r,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "g(r,t)_%s", update_partials=True, ) - self._outputData["4_pi_r2_g(r,t)_total"][:] = weight( + self._outputData["4_pi_r2_g(r,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "4_pi_r2_g(r,t)_%s", diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py index dd3247ec2..e3641cf4b 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py @@ -18,7 +18,7 @@ from scipy.signal import correlate from MDANSE.Framework.Jobs.IJob import IJob -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum from MDANSE.Mathematics.Signal import differentiate, normalize from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms @@ -211,15 +211,16 @@ def finalize(self): weights = self.configuration["weights"].get_weights() weight_dict = get_weights(weights, nAtomsPerElement, 1) - vacfTotal = weight(self._outputData, weight_dict, "vacf_%s") + assign_weights(self._outputData, weight_dict, "vacf_%s") + vacfTotal = weighted_sum(self._outputData, weight_dict, "vacf_%s") self._outputData["vacf_total"][:] = vacfTotal if self.configuration["normalize"]["value"]: for element in nAtomsPerElement.keys(): - self._outputData["vacf_%s" % element] = normalize( + self._outputData["vacf_%s" % element][:] = normalize( self._outputData["vacf_%s" % element], axis=0 ) - self._outputData["vacf_total"] = normalize( + self._outputData["vacf_total"][:] = normalize( self._outputData["vacf_total"], axis=0 ) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py index 1b23c0bb7..bda22228c 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py @@ -20,7 +20,7 @@ from MDANSE.Chemistry import ATOMS_DATABASE from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram -from MDANSE.Mathematics.Arithmetic import weight, get_weights +from MDANSE.Mathematics.Arithmetic import assign_weights, get_weights, weighted_sum def atomic_scattering_factor(element, qvalues): @@ -196,10 +196,12 @@ def finalize(self): for k in list(nAtomsPerElement.keys()) ) weight_dict = get_weights(asf, nAtomsPerElement, 2) - xssfIntra = weight(self._outputData, weight_dict, "xssf_intra_%s%s") + assign_weights(self._outputData, weight_dict, "xssf_intra_%s") + assign_weights(self._outputData, weight_dict, "xssf_inter_%s") + xssfIntra = weighted_sum(self._outputData, weight_dict, "xssf_intra_%s%s") self._outputData["xssf_intra"][:] = xssfIntra - xssfInter = weight(self._outputData, weight_dict, "xssf_inter_%s%s") + xssfInter = weighted_sum(self._outputData, weight_dict, "xssf_inter_%s%s") self._outputData["xssf_inter"][:] = xssfInter self._outputData["xssf_total"][:] = xssfIntra + xssfInter diff --git a/MDANSE/Src/MDANSE/Framework/OutputVariables/IOutputVariable.py b/MDANSE/Src/MDANSE/Framework/OutputVariables/IOutputVariable.py index 35508e6e0..b0fb327a1 100644 --- a/MDANSE/Src/MDANSE/Framework/OutputVariables/IOutputVariable.py +++ b/MDANSE/Src/MDANSE/Framework/OutputVariables/IOutputVariable.py @@ -60,7 +60,7 @@ def __new__( partial_result=False, ): """ - Instanciate a new MDANSE output variable. + Instantiate a new MDANSE output variable. @param cls: the class to instantiate. @type cls: an OutputVariable object @@ -97,6 +97,8 @@ def __new__( obj.axis = axis + obj.scaling_factor = 1.0 + data_tags = [] if main_result: data_tags.append("main") diff --git a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py index 7e3a6173e..d45da03d3 100644 --- a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py +++ b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py @@ -66,12 +66,11 @@ def get_weights(props: Dict[str, float], contents: Dict[str, int], dim: int): return weights -def weight( +def assign_weights( values: Dict[str, np.ndarray], weights: Dict[str, float], key: str, symmetric: bool = True, - update_partials: bool = False, ): """_summary_ @@ -97,22 +96,58 @@ def weight( matches = dict([(key % k, k) for k in list(weights.keys()) if k not in ["sum"]]) dim = key.count("%s") - for k, val in values.items(): + for k in values.keys(): if k not in matches: continue if symmetric: permutations = set(itertools.permutations(matches[k], r=dim)) - w = sum([weights.pop(p) for p in permutations]) + w = sum([weights[p] for p in permutations]) else: - w = weights.pop(matches[k]) + w = weights[matches[k]] + + values[k].scaling_factor *= w + + return weightedSum + + +def weighted_sum( + values: Dict[str, np.ndarray], + weights: Dict[str, float], + key: str, + update_partials: bool = False, +): + """_summary_ + + Parameters + ---------- + values : Dict[str, np.ndarray] + Dictionary of data arrays containing analysis results. + weights : Dict[str, float] + Dictionary of scaling factors per dataset + key : str + A string data set name with formatting elements (placeholders for chemical element labels) + update_partials : bool, optional + Partial results will be rescaled if this is true, by default False + + Returns + ------- + np.ndarray + total sum of all the component arrays scaled by their weights + """ + weightedSum = None + matches = dict([(key % k, k) for k in list(weights.keys()) if k not in ["sum"]]) + + for k, val in values.items(): + if k not in matches: + continue if weightedSum is None: - weightedSum = w * val + weightedSum = val * val.scaling_factor else: - weightedSum += w * val + weightedSum += val * val.scaling_factor if update_partials: - values[k][:] = w * val + values[k][:] = val * val.scaling_factor return weightedSum diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/PlottingContext.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/PlottingContext.py index 5ea30bc5e..28b9d23e9 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/PlottingContext.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Models/PlottingContext.py @@ -60,6 +60,7 @@ class SingleDataset: def __init__(self, name: str, source: "h5py.File"): self._name = name self._filename = source.filename + self._use_scaling = True self._curves = {} self._curve_labels = {} self._planes = {} @@ -85,6 +86,11 @@ def __init__(self, name: str, source: "h5py.File"): self._data_unit = source[name].attrs["units"] self._n_dim = len(self._data.shape) self._axes_tag = source[name].attrs["axis"] + self._scaling_factor = 1.0 + try: + self._scaling_factor = float(source[name].attrs["scaling_factor"]) + except KeyError: + pass self._axes = {} self._axes_units = {} for ax_number, axis_name in enumerate(self._axes_tag.split("|")): @@ -145,6 +151,12 @@ def longest_axis(self) -> str: best_axis = aname return best_unit, best_axis + @property + def data(self): + if self._use_scaling: + return self._data * self._scaling_factor + return self._data + def curves_vs_axis(self, axis_unit: str) -> List[np.ndarray]: self._curves = {} self._curve_labels = {} @@ -173,10 +185,21 @@ def curves_vs_axis(self, axis_unit: str) -> List[np.ndarray]: for n in range(len(indices)): if self._data_limits is not None: if n in self._data_limits: - self._curves[tuple(indices[n])] = self._data[slicers[n]].squeeze() + if self._use_scaling: + temp_data = ( + self._data[slicers[n]].squeeze() * self._scaling_factor + ) + else: + temp_data = self._data[slicers[n]].squeeze() + self._curves[tuple(indices[n])] = temp_data self._curve_labels[tuple(indices[n])] = str(tuple(indices[n])) else: - self._curves[tuple(indices[n])] = self._data[slicers[n]].squeeze() + if self._use_scaling: + self._curves[tuple(indices[n])] = ( + self._data[slicers[n]].squeeze() * self._scaling_factor + ) + else: + self._curves[tuple(indices[n])] = self._data[slicers[n]].squeeze() self._curve_labels[tuple(indices[n])] = str(tuple(indices[n])) return self._curves # slicer = tuple(slicer) @@ -194,7 +217,7 @@ def planes_vs_axis(self, axis_number: int) -> List[np.ndarray]: if total_ndim == 1: return elif total_ndim == 2: - return self._data + return self.data data_shape = self._data.shape number_of_planes = data_shape[axis_number] perpendicular_axis = None @@ -213,7 +236,10 @@ def planes_vs_axis(self, axis_number: int) -> List[np.ndarray]: fixed_argument = perpendicular_axis[plane_number] slice_def[axis_number] = plane_number data = self._data[tuple(slice_def)] - self._planes[plane_number] = data + if self._use_scaling: + self._planes[plane_number] = data * self._scaling_factor + else: + self._planes[plane_number] = data self._plane_labels[plane_number] = ( f"{perpendicular_axis_name}={fixed_argument}" ) @@ -221,7 +247,10 @@ def planes_vs_axis(self, axis_number: int) -> List[np.ndarray]: fixed_argument = perpendicular_axis[plane_number] slice_def[axis_number] = plane_number data = self._data[tuple(slice_def)] - self._planes[plane_number] = data + if self._use_scaling: + self._planes[plane_number] = data * self._scaling_factor + else: + self._planes[plane_number] = data self._plane_labels[plane_number] = ( f"{perpendicular_axis_name}={fixed_argument}" ) diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Single.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Single.py index 0dba100ea..33813b21e 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Single.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Single.py @@ -152,7 +152,7 @@ def plot( if dataset._n_dim == 1: [temp] = axes.plot( dataset._axes[best_axis] * conversion_factor, - dataset._data, + dataset.data, linestyle=linestyle, label=plotlabel, color=colour, diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Text.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Text.py index 9a8aad707..86a6888f5 100644 --- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Text.py +++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Plotters/Text.py @@ -198,12 +198,12 @@ def process_1D_data( [ dataset._axes[best_axis][: self._preview_lines] * conversion_factor, - dataset._data[: self._preview_lines], + dataset.data[: self._preview_lines], ] ).T else: temp = np.vstack( - [dataset._axes[best_axis] * conversion_factor, dataset._data] + [dataset._axes[best_axis] * conversion_factor, dataset.data] ).T return header_lines, temp @@ -262,7 +262,7 @@ def process_2D_data( temp = np.hstack( [ new_axes[axis_numbers[0]][:nlines].reshape((nlines, 1)), - dataset._data[:nlines, :ncols], + dataset.data[:nlines, :ncols], ] ) temp = np.vstack( @@ -277,7 +277,7 @@ def process_2D_data( temp = np.hstack( [ new_axes[axis_numbers[0]].reshape((dataset._data.shape[0], 1)), - dataset._data, + dataset.data, ] ) temp = np.vstack( @@ -332,7 +332,7 @@ def process_ND_data( new_axes[axis_numbers[axis_number]][index] for axis_number, index in enumerate(array_index) ] - yval = dataset._data[array_index] + yval = dataset.data[array_index] temp.append(xvals + [yval]) counter += 1 return header_lines, np.vstack(temp) From c21a2bc9ab97cbce60ed5f5391b2920ef9260fe1 Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Mon, 16 Dec 2024 17:12:32 +0000 Subject: [PATCH 6/7] Change disf and dscf scaling --- .../MDANSE/Framework/Jobs/DensityOfStates.py | 4 +- .../Jobs/DynamicCoherentStructureFactor.py | 18 +++--- .../Jobs/DynamicIncoherentStructureFactor.py | 16 ++--- .../Jobs/ElasticIncoherentStructureFactor.py | 2 +- ...aussianDynamicIncoherentStructureFactor.py | 4 +- .../NeutronDynamicTotalStructureFactor.py | 58 ++++++++++++------- .../Framework/Jobs/PositionPowerSpectrum.py | 4 +- .../Framework/Jobs/VanHoveFunctionSelf.py | 4 +- 8 files changed, 67 insertions(+), 43 deletions(-) diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py b/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py index 42c2c1c4a..dd6415b8a 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DensityOfStates.py @@ -245,13 +245,13 @@ def finalize(self): self._outputData, weight_dict, "vacf_%s", - update_partials=True, + update_partials=False, ) self._outputData["dos_total"][:] = weighted_sum( self._outputData, weight_dict, "dos_%s", - update_partials=True, + update_partials=False, ) self._outputData.write( diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py index b2dc3271c..d25710b03 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicCoherentStructureFactor.py @@ -249,32 +249,36 @@ def finalize(self): """ nAtomsPerElement = self.configuration["atom_selection"].get_natoms() + + weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 2) + assign_weights(self._outputData, weight_dict, "f(q,t)_%s%s") + assign_weights(self._outputData, weight_dict, "s(q,f)_%s%s") for pair in self._elementsPairs: ni = nAtomsPerElement[pair[0]] nj = nAtomsPerElement[pair[1]] - self._outputData["f(q,t)_%s%s" % pair][:] /= np.sqrt(ni * nj) + extra_scaling = 1.0 / np.sqrt(ni * nj) + self._outputData["f(q,t)_%s%s" % pair].scaling_factor *= extra_scaling self._outputData["s(q,f)_%s%s" % pair][:] = get_spectrum( self._outputData["f(q,t)_%s%s" % pair], self.configuration["instrument_resolution"]["time_window"], self.configuration["instrument_resolution"]["time_step"], axis=1, ) - weights = self.configuration["weights"].get_weights() - weight_dict = get_weights(weights, nAtomsPerElement, 2) - assign_weights(self._outputData, weight_dict, "f(q,t)_%s%s") - assign_weights(self._outputData, weight_dict, "s(q,f)_%s%s") + self._outputData["s(q,f)_%s%s" % pair].scaling_factor *= extra_scaling + self._outputData["f(q,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "f(q,t)_%s%s", - update_partials=True, + update_partials=False, ) self._outputData["s(q,f)_total"][:] = weighted_sum( self._outputData, weight_dict, "s(q,f)_%s%s", - update_partials=True, + update_partials=False, ) self._outputData.write( diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py index 6d1a3c62b..859496038 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/DynamicIncoherentStructureFactor.py @@ -255,31 +255,33 @@ def finalize(self): """ nAtomsPerElement = self.configuration["atom_selection"].get_natoms() + weights = self.configuration["weights"].get_weights() + weight_dict = get_weights(weights, nAtomsPerElement, 1) + assign_weights(self._outputData, weight_dict, "f(q,t)_%s") + assign_weights(self._outputData, weight_dict, "s(q,f)_%s") for element, number in list(nAtomsPerElement.items()): - self._outputData["f(q,t)_%s" % element][:] /= number + extra_scaling = 1.0 / number + self._outputData["f(q,t)_%s" % element].scaling_factor *= extra_scaling self._outputData["s(q,f)_%s" % element][:] = get_spectrum( self._outputData["f(q,t)_%s" % element], self.configuration["instrument_resolution"]["time_window"], self.configuration["instrument_resolution"]["time_step"], axis=1, ) + self._outputData["s(q,f)_%s" % element].scaling_factor *= extra_scaling - weights = self.configuration["weights"].get_weights() - weight_dict = get_weights(weights, nAtomsPerElement, 1) - assign_weights(self._outputData, weight_dict, "f(q,t)_%s") - assign_weights(self._outputData, weight_dict, "s(q,f)_%s") self._outputData["f(q,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "f(q,t)_%s", - update_partials=True, + update_partials=False, ) self._outputData["s(q,f)_total"][:] = weighted_sum( self._outputData, weight_dict, "s(q,f)_%s", - update_partials=True, + update_partials=False, ) self._outputData.write( diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py index c7a3f44af..d021474b2 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/ElasticIncoherentStructureFactor.py @@ -204,7 +204,7 @@ def finalize(self): self._outputData, weight_dict, "eisf_%s", - update_partials=True, + update_partials=False, ) self._outputData.write( diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py index 974761553..f248f68d9 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/GaussianDynamicIncoherentStructureFactor.py @@ -257,14 +257,14 @@ def finalize(self): self._outputData, weight_dict, "f(q,t)_%s", - update_partials=True, + update_partials=False, ) self._outputData["s(q,f)_total"][:] = weighted_sum( self._outputData, weight_dict, "s(q,f)_%s", - update_partials=True, + update_partials=False, ) self._outputData.write( diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py index d953b6148..abcaeebf6 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py @@ -214,6 +214,15 @@ def initialize(self): raise NeutronDynamicTotalStructureFactorError( "Missing s(q,f) in dcsf input file" ) + if ( + "scaling_factor" + not in self.configuration["dcsf_input_file"]["instance"][ + "s(q,f)_{}{}".format(*pair) + ].attrs.keys() + ): + raise NeutronDynamicTotalStructureFactorError( + "This DCSF file was created before the new scaling scheme. Please calculate it again." + ) for element in self.configuration["atom_selection"]["unique_names"]: if ( @@ -230,6 +239,15 @@ def initialize(self): raise NeutronDynamicTotalStructureFactorError( "Missing s(q,f) in disf input file" ) + if ( + "scaling_factor" + not in self.configuration["disf_input_file"]["instance"][ + "s(q,f)_{}".format(element) + ].attrs.keys() + ): + raise NeutronDynamicTotalStructureFactorError( + "This DISF file was created before the new scaling scheme. Please calculate it again." + ) for element in self.configuration["atom_selection"]["unique_names"]: fqt = self.configuration["disf_input_file"]["instance"][ @@ -405,20 +423,24 @@ def finalize(self): # Compute coherent functions and structure factor for pair in self._elementsPairs: - if self._input_dcsf_weight == "equal": - bi = ATOMS_DATABASE.get_atom_property(pair[0], "b_coherent") - bj = ATOMS_DATABASE.get_atom_property(pair[1], "b_coherent") - elif self._input_dcsf_weight == "b_coherent": - bi = bj = 1.0 - else: - LOG.error("Input DCSF weights should be b_coherent or equal") - return + bi = ATOMS_DATABASE.get_atom_property(pair[0], "b_coherent") + bj = ATOMS_DATABASE.get_atom_property(pair[1], "b_coherent") + ni = nAtomsPerElement[pair[0]] + nj = nAtomsPerElement[pair[1]] + ci = ni / nTotalAtoms + cj = nj / nTotalAtoms self._outputData["f(q,t)_coh_weighted_%s%s" % pair][:] = ( - self._outputData["f(q,t)_coh_%s%s" % pair][:] * bi * bj + self._outputData["f(q,t)_coh_%s%s" % pair][:] + * np.sqrt(ci * cj) + * bi + * bj ) self._outputData["s(q,f)_coh_weighted_%s%s" % pair][:] = ( - self._outputData["s(q,f)_coh_%s%s" % pair][:] * bi * bj + self._outputData["s(q,f)_coh_%s%s" % pair][:] + * np.sqrt(ci * cj) + * bi + * bj ) if pair[0] == pair[1]: # Add a factor 2 if the two elements are different self._outputData["f(q,t)_coh_total"][:] += self._outputData[ @@ -436,20 +458,16 @@ def finalize(self): ) # Compute incoherent functions and structure factor - for element, _ in nAtomsPerElement.items(): - if self._input_disf_weight == "equal": - bi = ATOMS_DATABASE.get_atom_property(element, "b_incoherent2") - elif self._input_disf_weight == "b_incoherent2": - bi = 1.0 - else: - LOG.error("Input DCSF weights should be b_incoherent2 or equal") - return + for element, ni in nAtomsPerElement.items(): + bi = ATOMS_DATABASE.get_atom_property(element, "b_incoherent2") + ni = nAtomsPerElement[element] + ci = ni / nTotalAtoms self._outputData["f(q,t)_inc_weighted_%s" % element][:] = ( - self._outputData["f(q,t)_inc_%s" % element][:] * bi + self._outputData["f(q,t)_inc_%s" % element][:] * ci * bi ) self._outputData["s(q,f)_inc_weighted_%s" % element][:] = ( - self._outputData["s(q,f)_inc_%s" % element][:] * bi + self._outputData["s(q,f)_inc_%s" % element][:] * ci * bi ) self._outputData["f(q,t)_inc_total"][:] += self._outputData[ diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py index 6041a64b2..1a81bbb31 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py @@ -226,13 +226,13 @@ def finalize(self): self._outputData, weight_dict, "pacf_%s", - update_partials=True, + update_partials=False, ) self._outputData["pps_total"][:] = weighted_sum( self._outputData, weight_dict, "pps_%s", - update_partials=True, + update_partials=False, ) self._outputData.write( diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py index 7aa5ce20e..18c71311c 100644 --- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py +++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py @@ -250,13 +250,13 @@ def finalize(self): self._outputData, weight_dict, "g(r,t)_%s", - update_partials=True, + update_partials=False, ) self._outputData["4_pi_r2_g(r,t)_total"][:] = weighted_sum( self._outputData, weight_dict, "4_pi_r2_g(r,t)_%s", - update_partials=True, + update_partials=False, ) self._outputData.write( From 8bd79099137af0895358c080076e041bb7573667 Mon Sep 17 00:00:00 2001 From: Maciej Bartkowiak Date: Tue, 17 Dec 2024 10:57:43 +0000 Subject: [PATCH 7/7] Update the docstrings in Arithmetic.py --- MDANSE/Src/MDANSE/Mathematics/Arithmetic.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py index d45da03d3..4ffa8ec48 100644 --- a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py +++ b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py @@ -20,8 +20,9 @@ def get_weights(props: Dict[str, float], contents: Dict[str, int], dim: int): - """Calculates the scaling factor to be applied to output datasets - of an analysis. + """Calculates the scaling factors to be applied to output datasets + of an analysis. Returns an dictionary of scaling factors, where the + chemical elements identifying each dataset are the keys. Parameters ---------- @@ -72,7 +73,8 @@ def assign_weights( key: str, symmetric: bool = True, ): - """_summary_ + """Updates the scaling factors of partial datasets, without + modifying the data. Parameters ---------- @@ -92,7 +94,6 @@ def assign_weights( np.ndarray total sum of all the component arrays scaled by their weights """ - weightedSum = None matches = dict([(key % k, k) for k in list(weights.keys()) if k not in ["sum"]]) dim = key.count("%s") @@ -108,8 +109,6 @@ def assign_weights( values[k].scaling_factor *= w - return weightedSum - def weighted_sum( values: Dict[str, np.ndarray], @@ -117,7 +116,9 @@ def weighted_sum( key: str, update_partials: bool = False, ): - """_summary_ + """Sums up partial datasets multiplied by their scaling factors. + The scaling factors have to be set before, typically by calling + the assign_weights function. Parameters ----------