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
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 | class Config:
def __init__(self, sett: dict):
self.__sett = copy.copy(sett)
self.__serial_data = None
self.__extract_attr()
self.__load_container()
self.__defaults()
self.__set_defaults()
self.__build()
def __extract_attr(self):
"""Extracts attributes that do not belong to a container.
This attributes are located at the first level of the input settings."""
if "ex" in self.__sett.keys():
self.__set_experimental(self.__sett.pop("ex"))
if "engine" in self.__sett.keys():
self.__set_attr(engine=self.__sett.pop("engine"))
def __load_container(self):
"""Load the container with the configuration dataclasses"""
# TODO: Extend to functionality for various containers
self.__container = importlib.import_module(
f"feniax.preprocessor.containers.{self.engine}"
)
self.__container = importlib.reload(self.__container) # remove after testing
def __defaults(self):
self.__MOD_DEFAULT = dict(optionsjax=["jax_np", "jax_scipy"])
self.__CONTAINER_DEFAULT = dict(intrinsicmodal=["const", "log"])
def __set_defaults(self):
# default modules
for k, v in self.__MOD_DEFAULT.items():
_container = importlib.import_module(f"feniax.preprocessor.containers.{k}")
for i in v:
container_k = getattr(_container, "".join(["D", i]))
if i in self.__sett.keys():
setattr(self, i, container_k(**self.__sett[i]))
del self.__sett[i]
else:
setattr(self, i, container_k())
# default containers within self.engine module
for k, vlist in self.__CONTAINER_DEFAULT.items():
if self.engine == k:
for v in vlist:
container_v = getattr(self.__container, "".join(["D", v]))
if v in self.__sett.keys():
setattr(self, v, container_v(**self.__sett[v]))
del self.__sett[v]
else:
setattr(self, v, container_v())
def __build(self):
if self.engine == "intrinsicmodal": # needs some specialisation here
k = "fem" # initialised fem first as it will be pass to system
v = self.__sett[k]
container_k = getattr(self.__container, "".join(["D", k]))
container_k_initialised = container_k(**v)
setattr(self, k, container_k_initialised)
for k, v in self.__sett.items():
if k != "fem" and v is not None: # avoid empty containers
container_k = getattr(self.__container, "".join(["D", k]))
if k == "systems" or k == "system": # pass Dfem
container_k_initialised = container_k(
**(v | dict(_fem=self.fem))
)
else:
container_k_initialised = container_k(**v)
setattr(self, k, container_k_initialised)
else: # not currently in used
for k, v in self.__sett.items():
container_k = getattr(self.__container, "".join(["D", k]))
setattr(self, k, container_k(**v))
def __set_experimental(self, experimental: dict):
ex_object = inputs.dict2object(experimental)
setattr(self, "ex", ex_object)
def __set_attr(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
@classmethod
def from_file(cls, file_dir: str | pathlib.Path, **kwargs):
yaml = YAML()
yaml_dict = yaml.load(pathlib.Path(file_dir))
return cls(yaml_dict)
def clone(self, add_attr:dict=None, del_attr:str|list=None):
self_dict = serialize_nocomments(self)
if add_attr is not None:
self_dict = feniax.utils.dict_merge(self_dict, add_attr)
if del_attr is not None:
if isinstance(del_attr, str):
feniax.utils.dict_deletebypath(self_dict, del_attr)
elif isinstance(del_attr, list):
for li in del_attr:
feniax.utils.dict_deletebypath(self_dict, li)
return Config(self_dict)
|