diff --git a/glotaran/builtin/io/yml/test/test_model_spec_kinetic.yml b/glotaran/builtin/io/yml/test/test_model_spec_kinetic.yml index 30cf67106..33b8c7058 100644 --- a/glotaran/builtin/io/yml/test/test_model_spec_kinetic.yml +++ b/glotaran/builtin/io/yml/test/test_model_spec_kinetic.yml @@ -56,7 +56,7 @@ megacomplex: k_matrix: [km1] # A megacomplex has one or more k-matrices cmplx2: k_matrix: [km2] - cmplx3: [[km3], None] + cmplx3: [[km3]] spectral_constraints: - type: zero diff --git a/glotaran/builtin/models/kinetic_image/initial_concentration.py b/glotaran/builtin/models/kinetic_image/initial_concentration.py index 35cce612e..1d6d952f4 100644 --- a/glotaran/builtin/models/kinetic_image/initial_concentration.py +++ b/glotaran/builtin/models/kinetic_image/initial_concentration.py @@ -6,7 +6,6 @@ import numpy as np -from glotaran.model import DatasetDescriptor from glotaran.model import model_attribute from glotaran.parameter import Parameter @@ -22,16 +21,8 @@ class InitialConcentration: """An initial concentration describes the population of the compartments at the beginning of an experiment.""" - def normalized(self, dataset: DatasetDescriptor) -> InitialConcentration: - parameters = self.parameters - for megacomplex in dataset.megacomplex: - scale = [ - megacomplex.scale - if c in megacomplex.involved_compartments and megacomplex.scale - else 1 - for c in self.compartments - ] - parameters = np.multiply(parameters, scale) + def normalized(self) -> InitialConcentration: + parameters = np.array(self.parameters) idx = [c not in self.exclude_from_normalize for c in self.compartments] parameters[idx] /= np.sum(parameters[idx]) new = copy.deepcopy(self) diff --git a/glotaran/builtin/models/kinetic_image/kinetic_image_dataset_descriptor.py b/glotaran/builtin/models/kinetic_image/kinetic_image_dataset_descriptor.py index 1bf07a405..86e6b847b 100644 --- a/glotaran/builtin/models/kinetic_image/kinetic_image_dataset_descriptor.py +++ b/glotaran/builtin/models/kinetic_image/kinetic_image_dataset_descriptor.py @@ -12,11 +12,38 @@ } ) class KineticImageDatasetDescriptor(DatasetDescriptor): - def get_k_matrices(self): - return [mat for mat in [cmplx.full_k_matrix() for cmplx in self.megacomplex] if mat] + def get_megacomplex_k_matrices(self): + scales = ( + [ + self.megacomplex_scale[i] + for i in [ + i + for i, megacomplex in enumerate(self.megacomplex) + if megacomplex.has_k_matrix() + ] + ] + if self.megacomplex_scale is not None + else None + ) + + matrices = [ + matrix + for matrix in [ + megacomplex.full_k_matrix() + for megacomplex in self.megacomplex + if megacomplex.has_k_matrix() + ] + ] + + return scales, matrices + + def has_k_matrix(self): + _, matrices = self.get_megacomplex_k_matrices() + return len(matrices) != 0 def compartments(self): compartments = [] - for k in self.get_k_matrices(): + _, k_matrices = self.get_megacomplex_k_matrices() + for k in k_matrices: compartments += k.involved_compartments() return list(set(compartments)) diff --git a/glotaran/builtin/models/kinetic_image/kinetic_image_matrix.py b/glotaran/builtin/models/kinetic_image/kinetic_image_matrix.py index 6a725710d..ab723990e 100644 --- a/glotaran/builtin/models/kinetic_image/kinetic_image_matrix.py +++ b/glotaran/builtin/models/kinetic_image/kinetic_image_matrix.py @@ -20,7 +20,7 @@ def kinetic_matrix( compartments = None matrix = None - k_matrices = dataset_descriptor.get_k_matrices() + megacomplex_scales, k_matrices = dataset_descriptor.get_megacomplex_k_matrices() if len(k_matrices) == 0: return (None, None) @@ -29,9 +29,9 @@ def kinetic_matrix( raise Exception( f'No initial concentration specified in dataset "{dataset_descriptor.label}"' ) - initial_concentration = dataset_descriptor.initial_concentration.normalized(dataset_descriptor) + initial_concentration = dataset_descriptor.initial_concentration.normalized() - for k_matrix in k_matrices: + for i, k_matrix in enumerate(k_matrices): if k_matrix is None: continue @@ -46,6 +46,9 @@ def kinetic_matrix( matrix_implementation, ) + if megacomplex_scales is not None: + this_matrix *= megacomplex_scales[i] + if matrix is None: compartments = this_compartments matrix = this_matrix diff --git a/glotaran/builtin/models/kinetic_image/kinetic_image_megacomplex.py b/glotaran/builtin/models/kinetic_image/kinetic_image_megacomplex.py index fdd00154e..0d090cae2 100644 --- a/glotaran/builtin/models/kinetic_image/kinetic_image_megacomplex.py +++ b/glotaran/builtin/models/kinetic_image/kinetic_image_megacomplex.py @@ -3,18 +3,19 @@ from typing import List from glotaran.model import model_attribute -from glotaran.parameter import Parameter @model_attribute( properties={ "k_matrix": {"type": List[str], "default": []}, - "scale": {"type": Parameter, "allow_none": True}, } ) class KineticImageMegacomplex: """A Megacomplex with one or more K-Matrices.""" + def has_k_matrix(self) -> bool: + return len(self.k_matrix) != 0 + def full_k_matrix(self, model=None): full_k_matrix = None for k_matrix in self.k_matrix: diff --git a/glotaran/builtin/models/kinetic_image/kinetic_image_result.py b/glotaran/builtin/models/kinetic_image/kinetic_image_result.py index eeb523716..e718f6ed3 100644 --- a/glotaran/builtin/models/kinetic_image/kinetic_image_result.py +++ b/glotaran/builtin/models/kinetic_image/kinetic_image_result.py @@ -12,7 +12,8 @@ def finalize_kinetic_image_result(model, problem: Problem, data: dict[str, xr.Da for label, dataset in data.items(): dataset_descriptor = problem.filled_dataset_descriptors[label] - if not dataset_descriptor.get_k_matrices(): + + if not dataset_descriptor.has_k_matrix(): continue retrieve_species_assocatiated_data(problem.model, dataset, dataset_descriptor, "images") diff --git a/glotaran/builtin/models/kinetic_spectrum/kinetic_spectrum_result.py b/glotaran/builtin/models/kinetic_spectrum/kinetic_spectrum_result.py index c70f8fb8b..8199c8746 100644 --- a/glotaran/builtin/models/kinetic_spectrum/kinetic_spectrum_result.py +++ b/glotaran/builtin/models/kinetic_spectrum/kinetic_spectrum_result.py @@ -17,7 +17,7 @@ def finalize_kinetic_spectrum_result(model, problem: Problem, data: dict[str, xr for label, dataset in data.items(): dataset_descriptor = problem.filled_dataset_descriptors[label] - if not dataset_descriptor.get_k_matrices(): + if not dataset_descriptor.has_k_matrix(): continue retrieve_species_assocatiated_data(problem.model, dataset, dataset_descriptor, "spectra") diff --git a/glotaran/model/dataset_descriptor.py b/glotaran/model/dataset_descriptor.py index 947b89528..fd39c35c7 100644 --- a/glotaran/model/dataset_descriptor.py +++ b/glotaran/model/dataset_descriptor.py @@ -10,6 +10,7 @@ @model_attribute( properties={ "megacomplex": List[str], + "megacomplex_scale": {"type": List[Parameter], "default": None, "allow_none": True}, "scale": {"type": Parameter, "default": None, "allow_none": True}, } ) diff --git a/glotaran/model/test/test_model.py b/glotaran/model/test/test_model.py index 31fa33dfd..c523c07e2 100644 --- a/glotaran/model/test/test_model.py +++ b/glotaran/model/test/test_model.py @@ -75,7 +75,7 @@ def model(): "megacomplex": ["m1", "m2"], "scale": "scale_1", }, - "dataset2": [["m2"], "scale_2"], + "dataset2": [["m2"], ["bar"], "scale_2"], }, } return MockModel.from_dict(d) @@ -98,7 +98,7 @@ def model_error(): "megacomplex": ["N1", "N2"], "scale": "scale_1", }, - "dataset2": [["mrX"], "scale_3"], + "dataset2": [["mrX"], ["bar"], "scale_3"], }, } return MockModel.from_dict(d)