Skip to content

material_density

MATERIAL_DEFAULTS = {'sld': {'description': 'The real scattering length density for a material in e-6 per squared angstrom.', 'url': 'https://www.ncnr.nist.gov/resources/activation/', 'value': 4.186, 'unit': '1 / angstrom^2', 'min': -np.inf, 'max': np.inf, 'fixed': True}, 'isld': {'description': 'The imaginary scattering length density for a material in e-6 per squared angstrom.', 'url': 'https://www.ncnr.nist.gov/resources/activation/', 'value': 0.0, 'unit': '1 / angstrom^2', 'min': -np.inf, 'max': np.inf, 'fixed': True}} module-attribute

DEFAULTS = {'chemical_structure': 'Si', 'density': {'description': 'The mass density of the material.', 'url': 'https://en.wikipedia.org/wiki/Density', 'value': 2.33, 'unit': 'gram / centimeter ** 3', 'min': 0, 'max': np.inf, 'fixed': True}, 'molecular_weight': {'description': 'The molecular weight of a material.', 'url': 'https://en.wikipedia.org/wiki/Molecular_mass', 'value': 28.02, 'unit': 'g / mole'}} module-attribute

Material

Bases: BaseCore

Source code in src/easyreflectometry/sample/elements/materials/material.py
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
class Material(BaseCore):
    def __init__(
        self,
        sld: Union[Parameter, float, None] = None,
        isld: Union[Parameter, float, None] = None,
        name: str = 'EasyMaterial',
        unique_name: Optional[str] = None,
        interface=None,
    ):
        """Constructor.

        Parameters
        ----------
        unique_name : Optional[str], optional
            By default, None.
        sld : Union[Parameter, float, None], optional
            Real scattering length density. By default, None.
        isld : Union[Parameter, float, None], optional
            Imaginary scattering length density. By default, None.
        name : str, optional
            Name of the material. By default, 'EasyMaterial'.
        interface :
            Calculator interface. By default, None.
        """
        if unique_name is None:
            unique_name = global_object.generate_unique_name(self.__class__.__name__)

        sld = get_as_parameter(
            name='sld',
            value=sld,
            default_dict=DEFAULTS,
            unique_name_prefix=f'{unique_name}_Sld',
        )
        apply_default_limits(sld, 'sld')

        isld = get_as_parameter(
            name='isld',
            value=isld,
            default_dict=DEFAULTS,
            unique_name_prefix=f'{unique_name}_Isld',
        )
        apply_default_limits(isld, 'isld')

        super().__init__(name=name, unique_name=unique_name)
        self._sld = sld
        self._isld = isld

        if interface is not None:
            self.interface = interface

    @property
    def sld(self) -> Parameter:
        return self._sld

    @sld.setter
    def sld(self, value: float) -> None:
        self._sld.value = value

    @property
    def isld(self) -> Parameter:
        return self._isld

    @isld.setter
    def isld(self, value: float) -> None:
        self._isld.value = value

    # Representation
    @property
    def _dict_repr(self) -> dict[str, str]:
        """A simplified dict representation."""
        return {
            self.name: {
                'sld': f'{self._sld.value:.3f}e-6 {self._sld.unit}',
                'isld': f'{self._isld.value:.3f}e-6 {self._isld.unit}',
            }
        }

__init__(sld=None, isld=None, name='EasyMaterial', unique_name=None, interface=None)

Constructor.

Parameters:

Name Type Description Default
unique_name Optional[str]

By default, None.

None
sld Union[Parameter, float, None]

Real scattering length density. By default, None.

None
isld Union[Parameter, float, None]

Imaginary scattering length density. By default, None.

None
name str

Name of the material. By default, 'EasyMaterial'.

'EasyMaterial'
interface

Calculator interface. By default, None.

None
Source code in src/easyreflectometry/sample/elements/materials/material.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def __init__(
    self,
    sld: Union[Parameter, float, None] = None,
    isld: Union[Parameter, float, None] = None,
    name: str = 'EasyMaterial',
    unique_name: Optional[str] = None,
    interface=None,
):
    """Constructor.

    Parameters
    ----------
    unique_name : Optional[str], optional
        By default, None.
    sld : Union[Parameter, float, None], optional
        Real scattering length density. By default, None.
    isld : Union[Parameter, float, None], optional
        Imaginary scattering length density. By default, None.
    name : str, optional
        Name of the material. By default, 'EasyMaterial'.
    interface :
        Calculator interface. By default, None.
    """
    if unique_name is None:
        unique_name = global_object.generate_unique_name(self.__class__.__name__)

    sld = get_as_parameter(
        name='sld',
        value=sld,
        default_dict=DEFAULTS,
        unique_name_prefix=f'{unique_name}_Sld',
    )
    apply_default_limits(sld, 'sld')

    isld = get_as_parameter(
        name='isld',
        value=isld,
        default_dict=DEFAULTS,
        unique_name_prefix=f'{unique_name}_Isld',
    )
    apply_default_limits(isld, 'isld')

    super().__init__(name=name, unique_name=unique_name)
    self._sld = sld
    self._isld = isld

    if interface is not None:
        self.interface = interface

MaterialDensity

Bases: Material

A material defined by chemical formula and mass density.

The scattering length density is derived rather than set: from the formula, the coherent neutron scattering length b (real and imaginary parts, tabulated per isotope) and the molecular weight M are computed, and sld/isld are wired as dependent parameters

sld = N_A * density * b / M

so density is the natural fit parameter and edits to the density or the formula propagate to the SLD automatically.

The coupling can be switched off per material via :attr:sld_coupled: when False, sld/isld are independent parameters that can be set and fitted directly, while density, molecular_weight and the scattering lengths stop affecting anything until the coupling is restored. Restoring it (sld_coupled = True) recomputes the SLDs from the current formula and density, discarding manually set values. The state round-trips through as_dict/from_dict, including the manual SLD values of a decoupled material; dictionaries from before this feature deserialize as coupled.

Assigning :attr:chemical_structure updates the scattering lengths and the molecular weight together; an invalid formula raises ValueError and leaves the material unchanged.

:attr:molecular_weight is a read-only DescriptorNumber, never a fit parameter: it is fully determined by the formula, and freeing it alongside density would make the fit degenerate (only density / molecular_weight enters the derived SLD).

Source code in src/easyreflectometry/sample/elements/materials/material_density.py
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
class MaterialDensity(Material):
    """A material defined by chemical formula and mass density.

    The scattering length density is derived rather than set: from the
    formula, the coherent neutron scattering length ``b`` (real and
    imaginary parts, tabulated per isotope) and the molecular weight ``M``
    are computed, and ``sld``/``isld`` are wired as *dependent* parameters

        sld = N_A * density * b / M

    so ``density`` is the natural fit parameter and edits to the density or
    the formula propagate to the SLD automatically.

    The coupling can be switched off per material via :attr:`sld_coupled`:
    when ``False``, ``sld``/``isld`` are independent parameters that can be
    set and fitted directly, while ``density``, ``molecular_weight`` and the
    scattering lengths stop affecting anything until the coupling is
    restored. Restoring it (``sld_coupled = True``) recomputes the SLDs from
    the current formula and density, discarding manually set values. The
    state round-trips through ``as_dict``/``from_dict``, including the
    manual SLD values of a decoupled material; dictionaries from before
    this feature deserialize as coupled.

    Assigning :attr:`chemical_structure` updates the scattering lengths and
    the molecular weight together; an invalid formula raises ``ValueError``
    and leaves the material unchanged.

    :attr:`molecular_weight` is a read-only ``DescriptorNumber``, never a fit
    parameter: it is fully determined by the formula, and freeing it alongside
    density would make the fit degenerate (only ``density / molecular_weight``
    enters the derived SLD).
    """

    def __init__(
        self,
        chemical_structure: Union[str, None] = None,
        density: Union[Parameter, float, None] = None,
        name: str = 'EasyMaterialDensity',
        unique_name: Optional[str] = None,
        interface=None,
    ):
        """Constructor.

        Parameters
        ----------
        unique_name : Optional[str], optional
            By default, None.
        chemical_structure : Union[str, None], optional
            Chemical formula for the material. By default, None.
        density : Union[Parameter, float, None], optional
            Mass density for the material. By default, None.
        name : str, optional
            Identifier. By default, 'EasyMaterialDensity'.
        interface :
            Interface object. By default, None.
        """
        if unique_name is None:
            unique_name = global_object.generate_unique_name(self.__class__.__name__)

        if chemical_structure is None:
            chemical_structure = DEFAULTS['chemical_structure']

        density = get_as_parameter(
            name='density',
            value=density,
            default_dict=DEFAULTS,
            unique_name_prefix=f'{unique_name}_Density',
        )

        scattering_length = neutron_scattering_length(chemical_structure)

        mw = DescriptorNumber(
            name='molecular_weight',
            value=molecular_weight(chemical_structure),
            unit=DEFAULTS['molecular_weight']['unit'],
            description=DEFAULTS['molecular_weight']['description'],
            url=DEFAULTS['molecular_weight']['url'],
            unique_name=global_object.generate_unique_name(f'{unique_name}_Mw'),
        )
        scattering_length_real = get_as_parameter(
            name='scattering_length_real',
            value=scattering_length.real,
            default_dict=DEFAULTS['sld'],
            unique_name_prefix=f'{unique_name}_ScatteringLengthReal',
        )
        scattering_length_imag = get_as_parameter(
            name='scattering_length_imag',
            value=scattering_length.imag,
            default_dict=DEFAULTS['isld'],
            unique_name_prefix=f'{unique_name}_ScatteringLengthImag',
        )
        sld = get_as_parameter(
            name='sld',
            value=density_to_sld(scattering_length_real.value, mw.value, density.value),
            default_dict=DEFAULTS,
            unique_name_prefix=f'{unique_name}_Sld',
        )
        isld = get_as_parameter(
            name='isld',
            value=density_to_sld(scattering_length_imag.value, mw.value, density.value),
            default_dict=DEFAULTS,
            unique_name_prefix=f'{unique_name}_Isld',
        )

        dependency_expression = '1e-23*(0.602214076e6 * d * sl) / mw'
        dependency_map = {'d': density, 'sl': scattering_length_real, 'mw': mw}
        sld.make_dependent_on(dependency_expression=dependency_expression, dependency_map=dependency_map)

        dependency_map = {'d': density, 'sl': scattering_length_imag, 'mw': mw}
        isld.make_dependent_on(dependency_expression=dependency_expression, dependency_map=dependency_map)

        super().__init__(sld=sld, isld=isld, name=name, unique_name=unique_name, interface=None)

        self._scattering_length_real = scattering_length_real
        self._scattering_length_imag = scattering_length_imag
        self._molecular_weight = mw
        self._density = density
        self._chemical_structure = chemical_structure

        if interface is not None:
            self.interface = interface

    def _setup_sld_constraints(self) -> None:
        """Wire the derived `sld` / `isld` to depend on the current density and
        scattering-length Parameters.

        Idempotent — invoked once from `__init__` and again from `from_dict`
        after :class:`ModelBase` has swapped in the saved Parameter objects.
        """
        for derived in (self._sld, self._isld):
            if not derived.independent:
                derived.make_independent()

        dependency_expression = '1e-23*(0.602214076e6 * d * sl) / mw'
        self._sld.make_dependent_on(
            dependency_expression=dependency_expression,
            dependency_map={
                'd': self._density,
                'sl': self._scattering_length_real,
                'mw': self._molecular_weight,
            },
        )
        self._isld.make_dependent_on(
            dependency_expression=dependency_expression,
            dependency_map={
                'd': self._density,
                'sl': self._scattering_length_imag,
                'mw': self._molecular_weight,
            },
        )

    @property
    def sld_coupled(self) -> bool:
        """Whether ``sld``/``isld`` are derived from formula & density (True,
        the default) or independent, directly editable/fittable parameters
        (False). The dependency state itself is the source of truth."""
        return not self._sld.independent

    @sld_coupled.setter
    def sld_coupled(self, couple: bool) -> None:
        if couple == self.sld_coupled:
            return
        if couple:
            # Recomputes sld/isld from the current density/scattering
            # length/molecular weight — manually set values are discarded.
            self._setup_sld_constraints()
        else:
            # make_independent raises on an already-independent parameter,
            # so guard each individually. Values are kept.
            for parameter in (self._sld, self._isld):
                if not parameter.independent:
                    parameter.make_independent()

    def _convert_to_dict(self, d: dict, serializer, skip: Optional[list] = None, **kwargs) -> dict:
        """Serializer hook (see ``SerializerBase._convert_to_dict``).

        ``sld``/``isld`` are not constructor arguments, so the argspec-driven
        encoder never persists them; in the decoupled state their manually
        entered or fitted values would be lost on save/load without this.
        """
        d['sld_coupled'] = self.sld_coupled
        if not self.sld_coupled:
            d['sld'] = self._sld.value
            d['isld'] = self._isld.value
        return d

    @classmethod
    def from_dict(cls, obj_dict: dict) -> 'MaterialDensity':
        """Re-attach sld/isld dependencies after deserialization.

        :class:`ModelBase.from_dict` re-points `self._density` at the
        deserialized Parameter (because `density` is a constructor argument);
        the constraint graph built in `__init__` still references the
        temporary Parameter created from the float kwarg. Rebuild here so
        `q.density = X` propagates to the derived SLDs.

        The keys written by ``_convert_to_dict`` are not constructor
        arguments and must be removed before the parent's ``cls(**data)``
        call; they are then used to restore the coupling state. A dict
        without them (pre-feature project files) restores as coupled.
        """
        obj_dict = dict(obj_dict)
        sld_coupled = obj_dict.pop('sld_coupled', True)
        manual_sld = obj_dict.pop('sld', None)
        manual_isld = obj_dict.pop('isld', None)

        instance = super().from_dict(obj_dict)
        if sld_coupled:
            instance._setup_sld_constraints()
        else:
            # __init__ wired the dependencies; undo them and restore the
            # saved manual values.
            instance.sld_coupled = False
            if manual_sld is not None:
                instance._sld.value = manual_sld
            if manual_isld is not None:
                instance._isld.value = manual_isld
        return instance

    @property
    def chemical_structure(self) -> str:
        """Get the chemical structure string."""
        return self._chemical_structure

    @chemical_structure.setter
    def chemical_structure(self, structure_string: str) -> None:
        """Set the chemical structure string.

        Parameters
        ----------
        structure_string : str
            String that defines the chemical structure.
        """
        # Derive everything before mutating any state: an invalid formula
        # must leave the material fully unchanged. periodictable parses
        # garbage to an *empty* formula (b=0, mw=0) instead of raising, and
        # mw=0 would put a division by zero into the sld dependency.
        scattering_length = neutron_scattering_length(structure_string)
        # The molecular weight enters the sld dependency alongside the
        # scattering length; leaving it at the old formula's value would make
        # the derived sld a mix of two formulas.
        mw = molecular_weight(structure_string)
        if not mw:
            raise ValueError(f'Invalid chemical formula: {structure_string!r}')
        self._chemical_structure = structure_string
        self._scattering_length_real.value = scattering_length.real
        self._scattering_length_imag.value = scattering_length.imag
        self._molecular_weight.value = mw

    @property
    def density(self) -> Parameter:
        return self._density

    @density.setter
    def density(self, value: float) -> None:
        self._density.value = value

    @property
    def molecular_weight(self) -> DescriptorNumber:
        """The molecular weight of the formula. A read-only descriptor, not a
        fittable parameter: it is a constant of the chemical formula and is
        recomputed whenever :attr:`chemical_structure` is assigned."""
        return self._molecular_weight

    @property
    def scattering_length_real(self) -> Parameter:
        return self._scattering_length_real

    @property
    def scattering_length_imag(self) -> Parameter:
        return self._scattering_length_imag

    @property
    def _dict_repr(self) -> dict[str, str]:
        """Dictionary representation of the instance."""
        mat_dict = super()._dict_repr
        mat_dict['chemical_structure'] = self._chemical_structure
        mat_dict['density'] = f'{self.density.value:.2e} {self.density.unit}'
        return mat_dict

sld_coupled property writable

Whether sld/isld are derived from formula & density (True, the default) or independent, directly editable/fittable parameters (False). The dependency state itself is the source of truth.

chemical_structure property writable

Get the chemical structure string.

molecular_weight property

The molecular weight of the formula. A read-only descriptor, not a fittable parameter: it is a constant of the chemical formula and is recomputed whenever :attr:chemical_structure is assigned.

__init__(chemical_structure=None, density=None, name='EasyMaterialDensity', unique_name=None, interface=None)

Constructor.

Parameters:

Name Type Description Default
unique_name Optional[str]

By default, None.

None
chemical_structure Union[str, None]

Chemical formula for the material. By default, None.

None
density Union[Parameter, float, None]

Mass density for the material. By default, None.

None
name str

Identifier. By default, 'EasyMaterialDensity'.

'EasyMaterialDensity'
interface

Interface object. By default, None.

None
Source code in src/easyreflectometry/sample/elements/materials/material_density.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def __init__(
    self,
    chemical_structure: Union[str, None] = None,
    density: Union[Parameter, float, None] = None,
    name: str = 'EasyMaterialDensity',
    unique_name: Optional[str] = None,
    interface=None,
):
    """Constructor.

    Parameters
    ----------
    unique_name : Optional[str], optional
        By default, None.
    chemical_structure : Union[str, None], optional
        Chemical formula for the material. By default, None.
    density : Union[Parameter, float, None], optional
        Mass density for the material. By default, None.
    name : str, optional
        Identifier. By default, 'EasyMaterialDensity'.
    interface :
        Interface object. By default, None.
    """
    if unique_name is None:
        unique_name = global_object.generate_unique_name(self.__class__.__name__)

    if chemical_structure is None:
        chemical_structure = DEFAULTS['chemical_structure']

    density = get_as_parameter(
        name='density',
        value=density,
        default_dict=DEFAULTS,
        unique_name_prefix=f'{unique_name}_Density',
    )

    scattering_length = neutron_scattering_length(chemical_structure)

    mw = DescriptorNumber(
        name='molecular_weight',
        value=molecular_weight(chemical_structure),
        unit=DEFAULTS['molecular_weight']['unit'],
        description=DEFAULTS['molecular_weight']['description'],
        url=DEFAULTS['molecular_weight']['url'],
        unique_name=global_object.generate_unique_name(f'{unique_name}_Mw'),
    )
    scattering_length_real = get_as_parameter(
        name='scattering_length_real',
        value=scattering_length.real,
        default_dict=DEFAULTS['sld'],
        unique_name_prefix=f'{unique_name}_ScatteringLengthReal',
    )
    scattering_length_imag = get_as_parameter(
        name='scattering_length_imag',
        value=scattering_length.imag,
        default_dict=DEFAULTS['isld'],
        unique_name_prefix=f'{unique_name}_ScatteringLengthImag',
    )
    sld = get_as_parameter(
        name='sld',
        value=density_to_sld(scattering_length_real.value, mw.value, density.value),
        default_dict=DEFAULTS,
        unique_name_prefix=f'{unique_name}_Sld',
    )
    isld = get_as_parameter(
        name='isld',
        value=density_to_sld(scattering_length_imag.value, mw.value, density.value),
        default_dict=DEFAULTS,
        unique_name_prefix=f'{unique_name}_Isld',
    )

    dependency_expression = '1e-23*(0.602214076e6 * d * sl) / mw'
    dependency_map = {'d': density, 'sl': scattering_length_real, 'mw': mw}
    sld.make_dependent_on(dependency_expression=dependency_expression, dependency_map=dependency_map)

    dependency_map = {'d': density, 'sl': scattering_length_imag, 'mw': mw}
    isld.make_dependent_on(dependency_expression=dependency_expression, dependency_map=dependency_map)

    super().__init__(sld=sld, isld=isld, name=name, unique_name=unique_name, interface=None)

    self._scattering_length_real = scattering_length_real
    self._scattering_length_imag = scattering_length_imag
    self._molecular_weight = mw
    self._density = density
    self._chemical_structure = chemical_structure

    if interface is not None:
        self.interface = interface

from_dict(obj_dict) classmethod

Re-attach sld/isld dependencies after deserialization.

:class:ModelBase.from_dict re-points self._density at the deserialized Parameter (because density is a constructor argument); the constraint graph built in __init__ still references the temporary Parameter created from the float kwarg. Rebuild here so q.density = X propagates to the derived SLDs.

The keys written by _convert_to_dict are not constructor arguments and must be removed before the parent's cls(**data) call; they are then used to restore the coupling state. A dict without them (pre-feature project files) restores as coupled.

Source code in src/easyreflectometry/sample/elements/materials/material_density.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
@classmethod
def from_dict(cls, obj_dict: dict) -> 'MaterialDensity':
    """Re-attach sld/isld dependencies after deserialization.

    :class:`ModelBase.from_dict` re-points `self._density` at the
    deserialized Parameter (because `density` is a constructor argument);
    the constraint graph built in `__init__` still references the
    temporary Parameter created from the float kwarg. Rebuild here so
    `q.density = X` propagates to the derived SLDs.

    The keys written by ``_convert_to_dict`` are not constructor
    arguments and must be removed before the parent's ``cls(**data)``
    call; they are then used to restore the coupling state. A dict
    without them (pre-feature project files) restores as coupled.
    """
    obj_dict = dict(obj_dict)
    sld_coupled = obj_dict.pop('sld_coupled', True)
    manual_sld = obj_dict.pop('sld', None)
    manual_isld = obj_dict.pop('isld', None)

    instance = super().from_dict(obj_dict)
    if sld_coupled:
        instance._setup_sld_constraints()
    else:
        # __init__ wired the dependencies; undo them and restore the
        # saved manual values.
        instance.sld_coupled = False
        if manual_sld is not None:
            instance._sld.value = manual_sld
        if manual_isld is not None:
            instance._isld.value = manual_isld
    return instance

get_as_parameter(name, value, default_dict, unique_name_prefix=None)

This function creates a parameter for the variable name.

A parameter has a value and metadata.

If the value already is a parameter, it is returned. If the value is a number, a parameter is created with this value and metadata from the dictionary. If the value is None, a parameter is created with the default value and metadata from the dictionary.

param value: The value to use for the parameter.  If None, the default value in the dictionary is used.
param name: The name of the parameter
param default_dict: Dictionary with entry for `name` containing the default value and metadata for the parameter
Source code in src/easyreflectometry/utils.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def get_as_parameter(
    name: str,
    value: Union[Parameter, Number, None],
    default_dict: dict,
    unique_name_prefix: Optional[str] = None,
) -> Parameter:
    """This function creates a parameter for the variable `name`.

        A parameter has a value and metadata.
    If the value already is a parameter, it is returned.
        If the value is a number, a parameter is created with this value and metadata from the dictionary.
        If the value is None, a parameter is created with the default value and metadata from the dictionary.

        param value: The value to use for the parameter.  If None, the default value in the dictionary is used.
        param name: The name of the parameter
        param default_dict: Dictionary with entry for `name` containing the default value and metadata for the parameter
    """
    # This is a parameter, return it
    if isinstance(value, Parameter):
        return value

    # Ensure we got the dictionary for the parameter with the given name
    # Should leave the passed dictionary unchanged
    if name not in default_dict:
        parameter_dict = deepcopy(default_dict)
    else:
        parameter_dict = deepcopy(default_dict[name])

    # Add specific unique name prefix if requested
    if unique_name_prefix is not None:
        parameter_dict['unique_name'] = global_object.generate_unique_name(unique_name_prefix + 'Parameter')

    if value is None:
        # Create a default parameter using both value and metadata from dictionary
        return Parameter(name, **parameter_dict)
    elif isinstance(value, Number):
        # Create a parameter using provided value and metadata from dictionary
        del parameter_dict['value']
        return Parameter(name, value, **parameter_dict)

    raise ValueError(f'{name} must be a Parameter, a number, or None.')