easyscience 0.6.1__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {easyscience-0.6.1 → easyscience-1.0.0}/PKG-INFO +5 -4
- {easyscience-0.6.1 → easyscience-1.0.0}/README.md +1 -1
- {easyscience-0.6.1 → easyscience-1.0.0}/pyproject.toml +4 -3
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Datasets/xarray.py +12 -13
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/Groups.py +15 -16
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/Inferface.py +29 -19
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/ObjectClasses.py +79 -57
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/Variable.py +54 -32
- easyscience-1.0.0/src/easyscience/Objects/job/analysis.py +64 -0
- easyscience-0.6.1/src/easyscience/Objects/Job/Job.py → easyscience-1.0.0/src/easyscience/Objects/job/job.py +6 -8
- easyscience-0.6.1/src/easyscience/Objects/Job/Theory.py → easyscience-1.0.0/src/easyscience/Objects/job/theoreticalmodel.py +3 -3
- easyscience-1.0.0/src/easyscience/Objects/new_variable/__init__.py +4 -0
- easyscience-1.0.0/src/easyscience/Objects/new_variable/descriptor_base.py +211 -0
- easyscience-1.0.0/src/easyscience/Objects/new_variable/descriptor_bool.py +70 -0
- easyscience-1.0.0/src/easyscience/Objects/new_variable/descriptor_number.py +399 -0
- easyscience-1.0.0/src/easyscience/Objects/new_variable/descriptor_str.py +69 -0
- easyscience-1.0.0/src/easyscience/Objects/new_variable/parameter.py +722 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/virtual.py +45 -52
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/classTools.py +19 -19
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/decorators.py +2 -2
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/io/template.py +3 -3
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/io/xml.py +19 -21
- easyscience-1.0.0/src/easyscience/__init__.py +28 -0
- easyscience-1.0.0/src/easyscience/__version__.py +1 -0
- {easyscience-0.6.1/src/easyscience/Fitting → easyscience-1.0.0/src/easyscience/fitting}/Constraints.py +120 -84
- easyscience-1.0.0/src/easyscience/fitting/__init__.py +8 -0
- easyscience-1.0.0/src/easyscience/fitting/available_minimizers.py +88 -0
- easyscience-1.0.0/src/easyscience/fitting/fitter.py +278 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/__init__.py +9 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/factory.py +43 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/minimizer_base.py +296 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/minimizer_bumps.py +273 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/minimizer_dfo.py +279 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/minimizer_lmfit.py +278 -0
- easyscience-1.0.0/src/easyscience/fitting/minimizers/utils.py +62 -0
- easyscience-1.0.0/src/easyscience/fitting/multi_fitter.py +135 -0
- easyscience-1.0.0/src/easyscience/global_object/__init__.py +4 -0
- easyscience-1.0.0/src/easyscience/global_object/global_object.py +69 -0
- easyscience-0.6.1/src/easyscience/Utils/Hugger/Property.py → easyscience-1.0.0/src/easyscience/global_object/hugger/property.py +39 -38
- easyscience-0.6.1/src/easyscience/Objects/Graph.py → easyscience-1.0.0/src/easyscience/global_object/map.py +87 -141
- easyscience-0.6.1/src/easyscience/Utils/UndoRedo.py → easyscience-1.0.0/src/easyscience/global_object/undo_redo.py +7 -7
- easyscience-0.6.1/src/easyscience/Fitting/DFO_LS.py +0 -288
- easyscience-0.6.1/src/easyscience/Fitting/Fitting.py +0 -473
- easyscience-0.6.1/src/easyscience/Fitting/__init__.py +0 -35
- easyscience-0.6.1/src/easyscience/Fitting/bumps.py +0 -314
- easyscience-0.6.1/src/easyscience/Fitting/fitting_template.py +0 -272
- easyscience-0.6.1/src/easyscience/Fitting/lmfit.py +0 -324
- easyscience-0.6.1/src/easyscience/Objects/Borg.py +0 -48
- easyscience-0.6.1/src/easyscience/Objects/Job/Analysis.py +0 -21
- easyscience-0.6.1/src/easyscience/Utils/io/star.py +0 -520
- easyscience-0.6.1/src/easyscience/Utils/typing.py +0 -14
- easyscience-0.6.1/src/easyscience/__init__.py +0 -18
- easyscience-0.6.1/src/easyscience/__version__.py +0 -1
- {easyscience-0.6.1 → easyscience-1.0.0}/.gitignore +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/LICENSE +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Datasets/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Objects/core.py +0 -0
- {easyscience-0.6.1/src/easyscience/Objects/Job → easyscience-1.0.0/src/easyscience/Objects/job}/__init__.py +0 -0
- /easyscience-0.6.1/src/easyscience/Objects/Job/Experiment.py → /easyscience-1.0.0/src/easyscience/Objects/job/experiment.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/REDIRECT.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/Exceptions.py +0 -0
- {easyscience-0.6.1/src/easyscience/Utils/Hugger → easyscience-1.0.0/src/easyscience/Utils}/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/classUtils.py +0 -0
- {easyscience-0.6.1/src/easyscience/Utils → easyscience-1.0.0/src/easyscience/Utils/io}/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/io/dict.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/io/json.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/Utils/string.py +0 -0
- {easyscience-0.6.1/src/easyscience/Utils/io → easyscience-1.0.0/src/easyscience/global_object/hugger}/__init__.py +0 -0
- /easyscience-0.6.1/src/easyscience/Utils/Hugger/Hugger.py → /easyscience-1.0.0/src/easyscience/global_object/hugger/hugger.py +0 -0
- /easyscience-0.6.1/src/easyscience/Utils/Logging.py → /easyscience-1.0.0/src/easyscience/global_object/logger.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/models/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-1.0.0}/src/easyscience/models/polynomial.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: easyscience
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Generic logic for easyScience libraries
|
|
5
5
|
Project-URL: homepage, https://docs.easyscience.org
|
|
6
6
|
Project-URL: documentation, https://docs.easyscience.org
|
|
@@ -51,8 +51,9 @@ Requires-Dist: asteval
|
|
|
51
51
|
Requires-Dist: bumps
|
|
52
52
|
Requires-Dist: dfo-ls
|
|
53
53
|
Requires-Dist: lmfit
|
|
54
|
-
Requires-Dist: numpy
|
|
55
|
-
Requires-Dist: pint
|
|
54
|
+
Requires-Dist: numpy==1.26
|
|
55
|
+
Requires-Dist: pint==0.23
|
|
56
|
+
Requires-Dist: scipp
|
|
56
57
|
Requires-Dist: uncertainties
|
|
57
58
|
Requires-Dist: xarray
|
|
58
59
|
Provides-Extra: dev
|
|
@@ -111,6 +112,6 @@ Documentation can be found at:
|
|
|
111
112
|
We absolutely welcome contributions. **EasyScience** is maintained by the ESS and on a volunteer basis and thus we need to foster a community that can support user questions and develop new features to make this software a useful tool for all users while encouraging every member of the community to share their ideas.
|
|
112
113
|
|
|
113
114
|
## License
|
|
114
|
-
While **EasyScience** is under the BSD-3 license,
|
|
115
|
+
While **EasyScience** is under the BSD-3 license, DFO-LS is subject to the GPL license.
|
|
115
116
|
|
|
116
117
|
|
|
@@ -35,6 +35,6 @@ Documentation can be found at:
|
|
|
35
35
|
We absolutely welcome contributions. **EasyScience** is maintained by the ESS and on a volunteer basis and thus we need to foster a community that can support user questions and develop new features to make this software a useful tool for all users while encouraging every member of the community to share their ideas.
|
|
36
36
|
|
|
37
37
|
## License
|
|
38
|
-
While **EasyScience** is under the BSD-3 license,
|
|
38
|
+
While **EasyScience** is under the BSD-3 license, DFO-LS is subject to the GPL license.
|
|
39
39
|
|
|
40
40
|
|
|
@@ -34,10 +34,11 @@ dependencies = [
|
|
|
34
34
|
"bumps",
|
|
35
35
|
"DFO-LS",
|
|
36
36
|
"lmfit",
|
|
37
|
-
"numpy",
|
|
38
|
-
"pint",
|
|
37
|
+
"numpy==1.26", # Should be updated to numpy 2.0
|
|
39
38
|
"uncertainties",
|
|
40
|
-
"xarray"
|
|
39
|
+
"xarray",
|
|
40
|
+
"pint==0.23", # Only to ensure that unit is reported as dimensionless rather than empty string
|
|
41
|
+
"scipp"
|
|
41
42
|
]
|
|
42
43
|
|
|
43
44
|
[project.optional-dependencies]
|
|
@@ -20,7 +20,7 @@ import numpy as np
|
|
|
20
20
|
import xarray as xr
|
|
21
21
|
|
|
22
22
|
from easyscience import ureg
|
|
23
|
-
from easyscience.
|
|
23
|
+
from easyscience.fitting import FitResults
|
|
24
24
|
|
|
25
25
|
T_ = TypeVar('T_')
|
|
26
26
|
|
|
@@ -281,14 +281,13 @@ class EasyScienceDatasetAccessor:
|
|
|
281
281
|
|
|
282
282
|
:param variable_label: Name of the DataArray to perform the calculation on
|
|
283
283
|
:type variable_label: str
|
|
284
|
-
:param sigma_func: Function to generate the sigmas. Must be of the form f(x) and return an array of the same
|
|
285
|
-
shape as the input. DEFAULT: sqrt(|data|)
|
|
284
|
+
:param sigma_func: Function to generate the sigmas. Must be of the form f(x) and return an array of the same shape as the input. Default sqrt(\|x\|)
|
|
286
285
|
:type sigma_func: Callable
|
|
287
286
|
:param label_prefix: What prefix should be used to designate a sigma DataArray from a data DataArray
|
|
288
287
|
:type label_prefix: str
|
|
289
288
|
:return: None
|
|
290
289
|
:rtype: None
|
|
291
|
-
"""
|
|
290
|
+
""" # noqa: E501
|
|
292
291
|
sigma_values = sigma_func(self._obj[variable_label])
|
|
293
292
|
self.sigma_attach(variable_label, sigma_values, label_prefix)
|
|
294
293
|
|
|
@@ -371,13 +370,13 @@ class EasyScienceDatasetAccessor:
|
|
|
371
370
|
**kwargs,
|
|
372
371
|
) -> List[FitResults]:
|
|
373
372
|
"""
|
|
374
|
-
Perform a fit on one or more DataArrays. This fit utilises a given fitter from `EasyScience.
|
|
373
|
+
Perform a fit on one or more DataArrays. This fit utilises a given fitter from `EasyScience.fitting.Fitter`, though
|
|
375
374
|
there are a few differences to a standard EasyScience fit. In particular, key-word arguments to control the
|
|
376
375
|
optimisation algorithm go in the `fit_kwargs` dictionary, fit function key-word arguments go in the `fn_kwargs`
|
|
377
376
|
and given key-word arguments control the `xarray.apply_ufunc` function.
|
|
378
377
|
|
|
379
378
|
:param fitter: Fitting object which controls the fitting
|
|
380
|
-
:type fitter: EasyScience.
|
|
379
|
+
:type fitter: EasyScience.fitting.Fitter
|
|
381
380
|
:param args: Arguments to go to the fit function
|
|
382
381
|
:type args: Any
|
|
383
382
|
:param dask: Dask control string. See `xarray.apply_ufunc` documentation
|
|
@@ -612,13 +611,13 @@ class EasyScienceDataarrayAccessor:
|
|
|
612
611
|
|
|
613
612
|
def fit_prep(self, func_in: Callable, bdims=None, dask_chunks=None) -> Tuple[xr.DataArray, Callable]:
|
|
614
613
|
"""
|
|
615
|
-
Generate
|
|
614
|
+
Generate broadcasted coordinates for fitting and reform the fitting function into one which can handle xarrays.
|
|
616
615
|
|
|
617
|
-
:param func_in: Function to be wrapped and made xarray fitting
|
|
616
|
+
:param func_in: Function to be wrapped and made xarray fitting compatible.
|
|
618
617
|
:type func_in: Callable
|
|
619
618
|
:param bdims: Optional precomputed broadcasted dimensions.
|
|
620
619
|
:type bdims: xarray.DataArray
|
|
621
|
-
:param dask_chunks: How to split
|
|
620
|
+
:param dask_chunks: How to split the broadcasted dimensions for dask.
|
|
622
621
|
:type dask_chunks: Tuple[int..]
|
|
623
622
|
:return: Tuple of broadcasted fit arrays and wrapped fit function.
|
|
624
623
|
:rtype: xarray.DataArray, Callable
|
|
@@ -681,13 +680,13 @@ class EasyScienceDataarrayAccessor:
|
|
|
681
680
|
**kwargs,
|
|
682
681
|
) -> FitResults:
|
|
683
682
|
"""
|
|
684
|
-
Perform a fit on the given DataArray. This fit utilises a given fitter from `EasyScience.
|
|
683
|
+
Perform a fit on the given DataArray. This fit utilises a given fitter from `EasyScience.fitting.Fitter`, though
|
|
685
684
|
there are a few differences to a standard EasyScience fit. In particular, key-word arguments to control the
|
|
686
685
|
optimisation algorithm go in the `fit_kwargs` dictionary, fit function key-word arguments go in the `fn_kwargs`
|
|
687
686
|
and given key-word arguments control the `xarray.apply_ufunc` function.
|
|
688
687
|
|
|
689
688
|
:param fitter: Fitting object which controls the fitting
|
|
690
|
-
:type fitter: EasyScience.
|
|
689
|
+
:type fitter: EasyScience.fitting.Fitter
|
|
691
690
|
:param args: Arguments to go to the fit function
|
|
692
691
|
:type args: Any
|
|
693
692
|
:param dask: Dask control string. See `xarray.apply_ufunc` documentation
|
|
@@ -732,7 +731,7 @@ class EasyScienceDataarrayAccessor:
|
|
|
732
731
|
|
|
733
732
|
# Set the new callable to the fitter and initialize
|
|
734
733
|
fitter.initialize(fitter.fit_object, local_fit_func)
|
|
735
|
-
# Make EasyScience.
|
|
734
|
+
# Make EasyScience.fitting.Fitter compatible `x`
|
|
736
735
|
x_for_fit = xr.concat(bdims, dim='fit_dim')
|
|
737
736
|
x_for_fit = x_for_fit.stack(all_x=[d.name for d in bdims])
|
|
738
737
|
try:
|
|
@@ -803,7 +802,7 @@ def check_sanity_multiple(fit_results: FitResults, originals: List[xr.DataArray]
|
|
|
803
802
|
current_results = fit_results.__class__()
|
|
804
803
|
# Fill out the basic stuff....
|
|
805
804
|
current_results.engine_result = fit_results.engine_result
|
|
806
|
-
current_results.
|
|
805
|
+
current_results.minimizer_engine = fit_results.minimizer_engine
|
|
807
806
|
current_results.success = fit_results.success
|
|
808
807
|
current_results.p = fit_results.p
|
|
809
808
|
current_results.p0 = fit_results.p0
|
|
@@ -17,15 +17,14 @@ from typing import Optional
|
|
|
17
17
|
from typing import Tuple
|
|
18
18
|
from typing import Union
|
|
19
19
|
|
|
20
|
-
from easyscience import
|
|
20
|
+
from easyscience.global_object.undo_redo import NotarizedDict
|
|
21
21
|
from easyscience.Objects.ObjectClasses import BasedBase
|
|
22
22
|
from easyscience.Objects.ObjectClasses import Descriptor
|
|
23
|
-
from easyscience.Utils.UndoRedo import NotarizedDict
|
|
24
23
|
|
|
25
24
|
if TYPE_CHECKING:
|
|
26
|
-
from easyscience.
|
|
27
|
-
from easyscience.
|
|
28
|
-
from easyscience.
|
|
25
|
+
from easyscience.Objects.Inferface import iF
|
|
26
|
+
from easyscience.Objects.ObjectClasses import B
|
|
27
|
+
from easyscience.Objects.Variable import V
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
class BaseCollection(BasedBase, MutableSequence):
|
|
@@ -75,8 +74,8 @@ class BaseCollection(BasedBase, MutableSequence):
|
|
|
75
74
|
for key, item in kwargs.items():
|
|
76
75
|
_kwargs[key] = item
|
|
77
76
|
for arg in args:
|
|
78
|
-
kwargs[
|
|
79
|
-
_kwargs[
|
|
77
|
+
kwargs[arg.unique_name] = arg
|
|
78
|
+
_kwargs[arg.unique_name] = arg
|
|
80
79
|
|
|
81
80
|
# Set kwargs, also useful for serialization
|
|
82
81
|
self._kwargs = NotarizedDict(**_kwargs)
|
|
@@ -84,8 +83,8 @@ class BaseCollection(BasedBase, MutableSequence):
|
|
|
84
83
|
for key in kwargs.keys():
|
|
85
84
|
if key in self.__dict__.keys() or key in self.__slots__:
|
|
86
85
|
raise AttributeError(f'Given kwarg: `{key}`, is an internal attribute. Please rename.')
|
|
87
|
-
self.
|
|
88
|
-
self.
|
|
86
|
+
self._global_object.map.add_edge(self, kwargs[key])
|
|
87
|
+
self._global_object.map.reset_type(kwargs[key], 'created_internal')
|
|
89
88
|
if interface is not None:
|
|
90
89
|
kwargs[key].interface = interface
|
|
91
90
|
# TODO wrap getter and setter in Logger
|
|
@@ -109,13 +108,13 @@ class BaseCollection(BasedBase, MutableSequence):
|
|
|
109
108
|
update_key = list(self._kwargs.keys())
|
|
110
109
|
values = list(self._kwargs.values())
|
|
111
110
|
# Update the internal dict
|
|
112
|
-
new_key =
|
|
111
|
+
new_key = value.unique_name
|
|
113
112
|
update_key.insert(index, new_key)
|
|
114
113
|
values.insert(index, value)
|
|
115
114
|
self._kwargs.reorder(**{k: v for k, v in zip(update_key, values)})
|
|
116
115
|
# ADD EDGE
|
|
117
|
-
self.
|
|
118
|
-
self.
|
|
116
|
+
self._global_object.map.add_edge(self, value)
|
|
117
|
+
self._global_object.map.reset_type(value, 'created_internal')
|
|
119
118
|
value.interface = self.interface
|
|
120
119
|
else:
|
|
121
120
|
raise AttributeError('Only EasyScience objects can be put into an EasyScience group')
|
|
@@ -174,11 +173,11 @@ class BaseCollection(BasedBase, MutableSequence):
|
|
|
174
173
|
update_dict = {update_key[key]: value}
|
|
175
174
|
self._kwargs.update(update_dict)
|
|
176
175
|
# ADD EDGE
|
|
177
|
-
self.
|
|
178
|
-
self.
|
|
176
|
+
self._global_object.map.add_edge(self, value)
|
|
177
|
+
self._global_object.map.reset_type(value, 'created_internal')
|
|
179
178
|
value.interface = self.interface
|
|
180
179
|
# REMOVE EDGE
|
|
181
|
-
self.
|
|
180
|
+
self._global_object.map.prune_vertex_from_edge(self, old_item)
|
|
182
181
|
else:
|
|
183
182
|
raise NotImplementedError('At the moment only numerical values or EasyScience objects can be set.')
|
|
184
183
|
|
|
@@ -193,7 +192,7 @@ class BaseCollection(BasedBase, MutableSequence):
|
|
|
193
192
|
"""
|
|
194
193
|
keys = list(self._kwargs.keys())
|
|
195
194
|
item = self._kwargs[keys[key]]
|
|
196
|
-
self.
|
|
195
|
+
self._global_object.map.prune_vertex_from_edge(self, item)
|
|
197
196
|
del self._kwargs[keys[key]]
|
|
198
197
|
|
|
199
198
|
def __len__(self) -> int:
|
|
@@ -4,8 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
5
5
|
# © 2021-2023 Contributors to the EasyScience project <https://github.com/easyScience/EasyScience
|
|
6
6
|
|
|
7
|
-
__author__ =
|
|
8
|
-
__version__ =
|
|
7
|
+
__author__ = 'github.com/wardsimon'
|
|
8
|
+
__version__ = '0.1.0'
|
|
9
9
|
|
|
10
10
|
from abc import ABCMeta
|
|
11
11
|
from typing import TYPE_CHECKING
|
|
@@ -16,10 +16,10 @@ from typing import Optional
|
|
|
16
16
|
from typing import Type
|
|
17
17
|
from typing import TypeVar
|
|
18
18
|
|
|
19
|
-
_C = TypeVar(
|
|
20
|
-
_M = TypeVar(
|
|
19
|
+
_C = TypeVar('_C', bound=ABCMeta)
|
|
20
|
+
_M = TypeVar('_M')
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
-
from easyscience.
|
|
22
|
+
from easyscience.fitting import Fitter
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class InterfaceFactoryTemplate:
|
|
@@ -44,14 +44,14 @@ class InterfaceFactoryTemplate:
|
|
|
44
44
|
:return: None
|
|
45
45
|
:rtype: noneType
|
|
46
46
|
"""
|
|
47
|
-
if kwargs.get(
|
|
47
|
+
if kwargs.get('interface_name', None) is None:
|
|
48
48
|
if len(self._interfaces) > 0:
|
|
49
49
|
# Fallback name
|
|
50
50
|
interface_name = self.return_name(self._interfaces[0])
|
|
51
51
|
else:
|
|
52
52
|
raise NotImplementedError
|
|
53
53
|
else:
|
|
54
|
-
interface_name = kwargs.pop(
|
|
54
|
+
interface_name = kwargs.pop('interface_name')
|
|
55
55
|
interfaces = self.available_interfaces
|
|
56
56
|
if interface_name in interfaces:
|
|
57
57
|
self._current_interface = self._interfaces[interfaces.index(interface_name)]
|
|
@@ -65,7 +65,7 @@ class InterfaceFactoryTemplate:
|
|
|
65
65
|
:param new_interface: name of new interface to be created
|
|
66
66
|
:type new_interface: str
|
|
67
67
|
:param fitter: Fitting interface which contains the fitting object which may have bindings which will be updated.
|
|
68
|
-
:type fitter: EasyScience.
|
|
68
|
+
:type fitter: EasyScience.fitting.Fitter
|
|
69
69
|
:return: None
|
|
70
70
|
:rtype: noneType
|
|
71
71
|
"""
|
|
@@ -74,20 +74,20 @@ class InterfaceFactoryTemplate:
|
|
|
74
74
|
self._current_interface = self._interfaces[interfaces.index(new_interface)]
|
|
75
75
|
self.__interface_obj = self._current_interface()
|
|
76
76
|
else:
|
|
77
|
-
raise AttributeError(
|
|
77
|
+
raise AttributeError('The user supplied interface is not valid.')
|
|
78
78
|
if fitter is not None:
|
|
79
|
-
if hasattr(fitter,
|
|
80
|
-
obj = getattr(fitter,
|
|
79
|
+
if hasattr(fitter, '_fit_object'):
|
|
80
|
+
obj = getattr(fitter, '_fit_object')
|
|
81
81
|
try:
|
|
82
|
-
if hasattr(obj,
|
|
82
|
+
if hasattr(obj, 'update_bindings'):
|
|
83
83
|
obj.update_bindings()
|
|
84
84
|
except Exception as e:
|
|
85
|
-
print(f
|
|
86
|
-
elif hasattr(fitter,
|
|
85
|
+
print(f'Unable to auto generate bindings.\n{e}')
|
|
86
|
+
elif hasattr(fitter, 'generate_bindings'):
|
|
87
87
|
try:
|
|
88
88
|
fitter.generate_bindings()
|
|
89
89
|
except Exception as e:
|
|
90
|
-
print(f
|
|
90
|
+
print(f'Unable to auto generate bindings.\n{e}')
|
|
91
91
|
|
|
92
92
|
@property
|
|
93
93
|
def available_interfaces(self) -> List[str]:
|
|
@@ -152,6 +152,8 @@ class InterfaceFactoryTemplate:
|
|
|
152
152
|
:return: binding property
|
|
153
153
|
:rtype: property
|
|
154
154
|
"""
|
|
155
|
+
import easyscience.Objects.new_variable.parameter
|
|
156
|
+
|
|
155
157
|
class_links = self.__interface_obj.create(model)
|
|
156
158
|
props = model._get_linkable_attributes()
|
|
157
159
|
props_names = [prop.name for prop in props]
|
|
@@ -161,8 +163,16 @@ class InterfaceFactoryTemplate:
|
|
|
161
163
|
continue
|
|
162
164
|
idx = props_names.index(item_key)
|
|
163
165
|
prop = props[idx]
|
|
166
|
+
|
|
167
|
+
## TODO clean when full move to new_variable
|
|
168
|
+
if isinstance(prop, easyscience.Objects.new_variable.parameter.Parameter):
|
|
169
|
+
# Should be fetched this way to ensure we don't get value from callback
|
|
170
|
+
prop_value = prop.value_no_call_back
|
|
171
|
+
else:
|
|
172
|
+
prop_value = prop.raw_value
|
|
173
|
+
|
|
164
174
|
prop._callback = item.make_prop(item_key)
|
|
165
|
-
prop._callback.fset(
|
|
175
|
+
prop._callback.fset(prop_value)
|
|
166
176
|
|
|
167
177
|
def __call__(self, *args, **kwargs) -> _M:
|
|
168
178
|
return self.__interface_obj
|
|
@@ -189,8 +199,8 @@ class InterfaceFactoryTemplate:
|
|
|
189
199
|
Return an interfaces name
|
|
190
200
|
"""
|
|
191
201
|
interface_name = this_interface.__name__
|
|
192
|
-
if hasattr(this_interface,
|
|
193
|
-
interface_name = getattr(this_interface,
|
|
202
|
+
if hasattr(this_interface, 'name'):
|
|
203
|
+
interface_name = getattr(this_interface, 'name')
|
|
194
204
|
return interface_name
|
|
195
205
|
|
|
196
206
|
|
|
@@ -225,4 +235,4 @@ class ItemContainer(NamedTuple):
|
|
|
225
235
|
return set_value
|
|
226
236
|
|
|
227
237
|
|
|
228
|
-
iF = TypeVar(
|
|
238
|
+
iF = TypeVar('iF', bound=InterfaceFactoryTemplate)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
__author__ =
|
|
4
|
-
__version__ =
|
|
3
|
+
__author__ = 'github.com/wardsimon'
|
|
4
|
+
__version__ = '0.1.0'
|
|
5
5
|
|
|
6
6
|
# SPDX-FileCopyrightText: 2023 EasyScience contributors <core@easyscience.software>
|
|
7
7
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
@@ -16,35 +16,41 @@ from typing import List
|
|
|
16
16
|
from typing import Optional
|
|
17
17
|
from typing import Set
|
|
18
18
|
from typing import TypeVar
|
|
19
|
+
from typing import Union
|
|
19
20
|
|
|
20
|
-
from easyscience import
|
|
21
|
+
from easyscience import global_object
|
|
21
22
|
from easyscience.Utils.classTools import addLoggedProp
|
|
22
23
|
|
|
23
24
|
from .core import ComponentSerializer
|
|
25
|
+
from .new_variable import Parameter as NewParameter
|
|
26
|
+
from .new_variable.descriptor_base import DescriptorBase
|
|
24
27
|
from .Variable import Descriptor
|
|
25
28
|
from .Variable import Parameter
|
|
26
29
|
|
|
27
30
|
if TYPE_CHECKING:
|
|
28
|
-
from easyscience.
|
|
29
|
-
from easyscience.
|
|
30
|
-
from easyscience.
|
|
31
|
+
from easyscience.fitting.Constraints import C
|
|
32
|
+
from easyscience.Objects.Inferface import iF
|
|
33
|
+
from easyscience.Objects.Variable import V
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
class BasedBase(ComponentSerializer):
|
|
34
|
-
__slots__ = [
|
|
37
|
+
__slots__ = ['_name', '_global_object', 'user_data', '_kwargs']
|
|
35
38
|
|
|
36
39
|
_REDIRECT = {}
|
|
37
40
|
|
|
38
|
-
def __init__(self, name: str, interface: Optional[iF] = None):
|
|
39
|
-
self.
|
|
40
|
-
|
|
41
|
+
def __init__(self, name: str, interface: Optional[iF] = None, unique_name: Optional[str] = None):
|
|
42
|
+
self._global_object = global_object
|
|
43
|
+
if unique_name is None:
|
|
44
|
+
unique_name = self._global_object.generate_unique_name(self.__class__.__name__)
|
|
45
|
+
self._unique_name = unique_name
|
|
46
|
+
self._name = name
|
|
47
|
+
self._global_object.map.add_vertex(self, obj_type='created')
|
|
41
48
|
self.interface = interface
|
|
42
49
|
self.user_data: dict = {}
|
|
43
|
-
self._name: str = name
|
|
44
50
|
|
|
45
51
|
@property
|
|
46
52
|
def _arg_spec(self) -> Set[str]:
|
|
47
|
-
base_cls = getattr(self,
|
|
53
|
+
base_cls = getattr(self, '__old_class__', self.__class__)
|
|
48
54
|
spec = getfullargspec(base_cls.__init__)
|
|
49
55
|
names = set(spec.args[1:])
|
|
50
56
|
return names
|
|
@@ -58,9 +64,24 @@ class BasedBase(ComponentSerializer):
|
|
|
58
64
|
:rtype: tuple
|
|
59
65
|
"""
|
|
60
66
|
state = self.encode()
|
|
61
|
-
cls = getattr(self,
|
|
67
|
+
cls = getattr(self, '__old_class__', self.__class__)
|
|
62
68
|
return cls.from_dict, (state,)
|
|
63
69
|
|
|
70
|
+
@property
|
|
71
|
+
def unique_name(self) -> str:
|
|
72
|
+
"""Get the unique name of the object."""
|
|
73
|
+
return self._unique_name
|
|
74
|
+
|
|
75
|
+
@unique_name.setter
|
|
76
|
+
def unique_name(self, new_unique_name: str):
|
|
77
|
+
"""Set a new unique name for the object. The old name is still kept in the map.
|
|
78
|
+
|
|
79
|
+
:param new_unique_name: New unique name for the object"""
|
|
80
|
+
if not isinstance(new_unique_name, str):
|
|
81
|
+
raise TypeError('Unique name has to be a string.')
|
|
82
|
+
self._unique_name = new_unique_name
|
|
83
|
+
self._global_object.map.add_vertex(self)
|
|
84
|
+
|
|
64
85
|
@property
|
|
65
86
|
def name(self) -> str:
|
|
66
87
|
"""
|
|
@@ -109,16 +130,14 @@ class BasedBase(ComponentSerializer):
|
|
|
109
130
|
:raises: AttributeError
|
|
110
131
|
"""
|
|
111
132
|
if self.interface is None:
|
|
112
|
-
raise AttributeError(
|
|
113
|
-
"Interface error for generating bindings. `interface` has to be set."
|
|
114
|
-
)
|
|
133
|
+
raise AttributeError('Interface error for generating bindings. `interface` has to be set.')
|
|
115
134
|
interfaceable_children = [
|
|
116
135
|
key
|
|
117
|
-
for key in self.
|
|
118
|
-
if issubclass(type(self.
|
|
136
|
+
for key in self._global_object.map.get_edges(self)
|
|
137
|
+
if issubclass(type(self._global_object.map.get_item_by_key(key)), BasedBase)
|
|
119
138
|
]
|
|
120
139
|
for child_key in interfaceable_children:
|
|
121
|
-
child = self.
|
|
140
|
+
child = self._global_object.map.get_item_by_key(child_key)
|
|
122
141
|
child.interface = self.interface
|
|
123
142
|
self.interface.generate_bindings(self)
|
|
124
143
|
|
|
@@ -127,9 +146,7 @@ class BasedBase(ComponentSerializer):
|
|
|
127
146
|
Switch or create a new interface.
|
|
128
147
|
"""
|
|
129
148
|
if self.interface is None:
|
|
130
|
-
raise AttributeError(
|
|
131
|
-
"Interface error for generating bindings. `interface` has to be set."
|
|
132
|
-
)
|
|
149
|
+
raise AttributeError('Interface error for generating bindings. `interface` has to be set.')
|
|
133
150
|
self.interface.switch(new_interface_name)
|
|
134
151
|
self.generate_bindings()
|
|
135
152
|
|
|
@@ -143,7 +160,8 @@ class BasedBase(ComponentSerializer):
|
|
|
143
160
|
constraints.append(con[key])
|
|
144
161
|
return constraints
|
|
145
162
|
|
|
146
|
-
|
|
163
|
+
## TODO clean when full move to new_variable
|
|
164
|
+
def get_parameters(self) -> Union[List[Parameter], List[NewParameter]]:
|
|
147
165
|
"""
|
|
148
166
|
Get all parameter objects as a list.
|
|
149
167
|
|
|
@@ -151,12 +169,13 @@ class BasedBase(ComponentSerializer):
|
|
|
151
169
|
"""
|
|
152
170
|
par_list = []
|
|
153
171
|
for key, item in self._kwargs.items():
|
|
154
|
-
if hasattr(item,
|
|
172
|
+
if hasattr(item, 'get_parameters'):
|
|
155
173
|
par_list = [*par_list, *item.get_parameters()]
|
|
156
|
-
elif isinstance(item, Parameter):
|
|
174
|
+
elif isinstance(item, Parameter) or isinstance(item, NewParameter):
|
|
157
175
|
par_list.append(item)
|
|
158
176
|
return par_list
|
|
159
177
|
|
|
178
|
+
## TODO clean when full move to new_variable
|
|
160
179
|
def _get_linkable_attributes(self) -> List[V]:
|
|
161
180
|
"""
|
|
162
181
|
Get all objects which can be linked against as a list.
|
|
@@ -165,13 +184,14 @@ class BasedBase(ComponentSerializer):
|
|
|
165
184
|
"""
|
|
166
185
|
item_list = []
|
|
167
186
|
for key, item in self._kwargs.items():
|
|
168
|
-
if hasattr(item,
|
|
187
|
+
if hasattr(item, '_get_linkable_attributes'):
|
|
169
188
|
item_list = [*item_list, *item._get_linkable_attributes()]
|
|
170
|
-
elif issubclass(type(item), Descriptor):
|
|
189
|
+
elif issubclass(type(item), Descriptor) or issubclass(type(item), DescriptorBase):
|
|
171
190
|
item_list.append(item)
|
|
172
191
|
return item_list
|
|
173
192
|
|
|
174
|
-
|
|
193
|
+
## TODO clean when full move to new_variable
|
|
194
|
+
def get_fit_parameters(self) -> Union[List[Parameter], List[NewParameter]]:
|
|
175
195
|
"""
|
|
176
196
|
Get all objects which can be fitted (and are not fixed) as a list.
|
|
177
197
|
|
|
@@ -179,10 +199,11 @@ class BasedBase(ComponentSerializer):
|
|
|
179
199
|
"""
|
|
180
200
|
fit_list = []
|
|
181
201
|
for key, item in self._kwargs.items():
|
|
182
|
-
if hasattr(item,
|
|
202
|
+
if hasattr(item, 'get_fit_parameters'):
|
|
183
203
|
fit_list = [*fit_list, *item.get_fit_parameters()]
|
|
184
|
-
elif isinstance(item, Parameter)
|
|
185
|
-
|
|
204
|
+
elif isinstance(item, Parameter) or isinstance(item, NewParameter):
|
|
205
|
+
if item.enabled and not item.fixed:
|
|
206
|
+
fit_list.append(item)
|
|
186
207
|
return fit_list
|
|
187
208
|
|
|
188
209
|
def __dir__(self) -> Iterable[str]:
|
|
@@ -191,13 +212,13 @@ class BasedBase(ComponentSerializer):
|
|
|
191
212
|
|
|
192
213
|
:return: list of function and parameter names for auto-completion
|
|
193
214
|
"""
|
|
194
|
-
new_class_objs = list(k for k in dir(self.__class__) if not k.startswith(
|
|
215
|
+
new_class_objs = list(k for k in dir(self.__class__) if not k.startswith('_'))
|
|
195
216
|
return sorted(new_class_objs)
|
|
196
217
|
|
|
197
218
|
|
|
198
219
|
if TYPE_CHECKING:
|
|
199
|
-
B = TypeVar(
|
|
200
|
-
BV = TypeVar(
|
|
220
|
+
B = TypeVar('B', bound=BasedBase)
|
|
221
|
+
BV = TypeVar('BV', bound=ComponentSerializer)
|
|
201
222
|
|
|
202
223
|
|
|
203
224
|
class BaseObj(BasedBase):
|
|
@@ -208,9 +229,11 @@ class BaseObj(BasedBase):
|
|
|
208
229
|
cheat with `BaseObj(*[Descriptor(...), Parameter(...), ...])`.
|
|
209
230
|
"""
|
|
210
231
|
|
|
232
|
+
## TODO clean when full move to new_variable
|
|
211
233
|
def __init__(
|
|
212
234
|
self,
|
|
213
235
|
name: str,
|
|
236
|
+
unique_name: Optional[str] = None,
|
|
214
237
|
*args: Optional[BV],
|
|
215
238
|
**kwargs: Optional[BV],
|
|
216
239
|
):
|
|
@@ -221,22 +244,22 @@ class BaseObj(BasedBase):
|
|
|
221
244
|
:param args: Any arguments?
|
|
222
245
|
:param kwargs: Fields which this class should contain
|
|
223
246
|
"""
|
|
224
|
-
super(BaseObj, self).__init__(name)
|
|
247
|
+
super(BaseObj, self).__init__(name=name, unique_name=unique_name)
|
|
225
248
|
# If Parameter or Descriptor is given as arguments...
|
|
226
249
|
for arg in args:
|
|
227
|
-
if issubclass(type(arg), (BaseObj, Descriptor)):
|
|
228
|
-
kwargs[getattr(arg,
|
|
250
|
+
if issubclass(type(arg), (BaseObj, Descriptor, DescriptorBase)):
|
|
251
|
+
kwargs[getattr(arg, 'name')] = arg
|
|
229
252
|
# Set kwargs, also useful for serialization
|
|
230
253
|
known_keys = self.__dict__.keys()
|
|
231
254
|
self._kwargs = kwargs
|
|
232
255
|
for key in kwargs.keys():
|
|
233
256
|
if key in known_keys:
|
|
234
|
-
raise AttributeError
|
|
235
|
-
if issubclass(
|
|
236
|
-
type(kwargs[key])
|
|
237
|
-
|
|
238
|
-
self.
|
|
239
|
-
self.
|
|
257
|
+
raise AttributeError('Kwargs cannot overwrite class attributes in BaseObj.')
|
|
258
|
+
if issubclass(type(kwargs[key]), (BasedBase, Descriptor, DescriptorBase)) or 'BaseCollection' in [
|
|
259
|
+
c.__name__ for c in type(kwargs[key]).__bases__
|
|
260
|
+
]:
|
|
261
|
+
self._global_object.map.add_edge(self, kwargs[key])
|
|
262
|
+
self._global_object.map.reset_type(kwargs[key], 'created_internal')
|
|
240
263
|
addLoggedProp(
|
|
241
264
|
self,
|
|
242
265
|
key,
|
|
@@ -269,8 +292,8 @@ class BaseObj(BasedBase):
|
|
|
269
292
|
:return: None
|
|
270
293
|
"""
|
|
271
294
|
self._kwargs[key] = component
|
|
272
|
-
self.
|
|
273
|
-
self.
|
|
295
|
+
self._global_object.map.add_edge(self, component)
|
|
296
|
+
self._global_object.map.reset_type(component, 'created_internal')
|
|
274
297
|
addLoggedProp(
|
|
275
298
|
self,
|
|
276
299
|
key,
|
|
@@ -281,31 +304,32 @@ class BaseObj(BasedBase):
|
|
|
281
304
|
test_class=BaseObj,
|
|
282
305
|
)
|
|
283
306
|
|
|
307
|
+
## TODO clean when full move to new_variable
|
|
284
308
|
def __setattr__(self, key: str, value: BV) -> None:
|
|
285
309
|
# Assume that the annotation is a ClassVar
|
|
286
310
|
old_obj = None
|
|
287
311
|
if (
|
|
288
|
-
hasattr(self.__class__,
|
|
312
|
+
hasattr(self.__class__, '__annotations__')
|
|
289
313
|
and key in self.__class__.__annotations__
|
|
290
|
-
and hasattr(self.__class__.__annotations__[key],
|
|
314
|
+
and hasattr(self.__class__.__annotations__[key], '__args__')
|
|
291
315
|
and issubclass(
|
|
292
|
-
getattr(value,
|
|
316
|
+
getattr(value, '__old_class__', value.__class__),
|
|
293
317
|
self.__class__.__annotations__[key].__args__,
|
|
294
318
|
)
|
|
295
319
|
):
|
|
296
|
-
if issubclass(type(getattr(self, key, None)), (BasedBase, Descriptor)):
|
|
320
|
+
if issubclass(type(getattr(self, key, None)), (BasedBase, Descriptor, DescriptorBase)):
|
|
297
321
|
old_obj = self.__getattribute__(key)
|
|
298
|
-
self.
|
|
322
|
+
self._global_object.map.prune_vertex_from_edge(self, old_obj)
|
|
299
323
|
self._add_component(key, value)
|
|
300
324
|
else:
|
|
301
|
-
if hasattr(self, key) and issubclass(type(value), (BasedBase, Descriptor)):
|
|
325
|
+
if hasattr(self, key) and issubclass(type(value), (BasedBase, Descriptor, DescriptorBase)):
|
|
302
326
|
old_obj = self.__getattribute__(key)
|
|
303
|
-
self.
|
|
304
|
-
self.
|
|
327
|
+
self._global_object.map.prune_vertex_from_edge(self, old_obj)
|
|
328
|
+
self._global_object.map.add_edge(self, value)
|
|
305
329
|
super(BaseObj, self).__setattr__(key, value)
|
|
306
330
|
# Update the interface bindings if something changed (BasedBase and Descriptor)
|
|
307
331
|
if old_obj is not None:
|
|
308
|
-
old_interface = getattr(self,
|
|
332
|
+
old_interface = getattr(self, 'interface', None)
|
|
309
333
|
if old_interface is not None:
|
|
310
334
|
self.generate_bindings()
|
|
311
335
|
|
|
@@ -322,9 +346,7 @@ class BaseObj(BasedBase):
|
|
|
322
346
|
@staticmethod
|
|
323
347
|
def __setter(key: str) -> Callable[[BV], None]:
|
|
324
348
|
def setter(obj: BV, value: float) -> None:
|
|
325
|
-
if issubclass(obj._kwargs[key].__class__, Descriptor) and not issubclass(
|
|
326
|
-
value.__class__, Descriptor
|
|
327
|
-
):
|
|
349
|
+
if issubclass(obj._kwargs[key].__class__, Descriptor) and not issubclass(value.__class__, Descriptor):
|
|
328
350
|
obj._kwargs[key].value = value
|
|
329
351
|
else:
|
|
330
352
|
obj._kwargs[key] = value
|