KratosOptimizationApplication 10.4.4__py3-none-any.whl
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.
- KratosMultiphysics/.libs/KratosOptimizationApplication.so +0 -0
- KratosMultiphysics/.libs/libKratosOptimizationCore.dylib +0 -0
- KratosMultiphysics/OptimizationApplication/__init__.py +19 -0
- KratosMultiphysics/OptimizationApplication/algorithms/NLOPT_algorithms.py +255 -0
- KratosMultiphysics/OptimizationApplication/algorithms/SciPy_algorithms.py +154 -0
- KratosMultiphysics/OptimizationApplication/algorithms/__init__.py +0 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm.py +78 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_adam.py +68 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_base.py +393 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_gradient_projection.py +355 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_momentum_relaxed_gradient_projection.py +70 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_nesterov_accelarated_gradient.py +60 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +263 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_steepest_descent.py +205 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_constraint.py +194 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_objective.py +191 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_constraint.py +123 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_objective.py +148 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_constraint.py +180 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_objective.py +133 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_rgp_constraint.py +268 -0
- KratosMultiphysics/OptimizationApplication/analyses_controller.py +75 -0
- KratosMultiphysics/OptimizationApplication/controls/control.py +123 -0
- KratosMultiphysics/OptimizationApplication/controls/external_response_function_control.py +149 -0
- KratosMultiphysics/OptimizationApplication/controls/master_control.py +198 -0
- KratosMultiphysics/OptimizationApplication/controls/material/material_properties_control.py +115 -0
- KratosMultiphysics/OptimizationApplication/controls/material/simp_control.py +229 -0
- KratosMultiphysics/OptimizationApplication/controls/shape/vertex_morphing_shape_control.py +289 -0
- KratosMultiphysics/OptimizationApplication/controls/thickness/shell_thickness_control.py +180 -0
- KratosMultiphysics/OptimizationApplication/controls_controller.py +205 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/avg_abs_improvement_conv_criterion.py +98 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/combined_conv_criterion.py +87 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/constraint_conv_criterion.py +68 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/convergence_criterion.py +26 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/l2_conv_criterion.py +77 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/magnitude_reduction_conv_criterion.py +85 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/max_iter_conv_criterion.py +48 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/patience_conv_criterion.py +116 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/target_value_conv_criterion.py +64 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy.py +46 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy_decorator.py +67 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/independent_analysis_execution_policy.py +78 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/kratos_analysis_execution_policy.py +137 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/stepping_analysis_execution_policy.py +88 -0
- KratosMultiphysics/OptimizationApplication/filtering/explicit_filter.py +124 -0
- KratosMultiphysics/OptimizationApplication/filtering/filter.py +188 -0
- KratosMultiphysics/OptimizationApplication/filtering/filter_utils.py +55 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_analysis.py +139 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_scalar_solver.py +39 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_shape_solver.py +67 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_solver_base.py +275 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_vector_solver.py +39 -0
- KratosMultiphysics/OptimizationApplication/filtering/implicit_filter.py +192 -0
- KratosMultiphysics/OptimizationApplication/filtering/python_solvers_wrapper_implicit_filters.py +56 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/connectivity_preserving_model_part_controller.py +72 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/external_response_function_model_part_controller.py +110 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/mdpa_model_part_controller.py +44 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/model_part_controller.py +19 -0
- KratosMultiphysics/OptimizationApplication/model_parts_controller.py +92 -0
- KratosMultiphysics/OptimizationApplication/optimization_analysis.py +146 -0
- KratosMultiphysics/OptimizationApplication/optimizations_controller.py +223 -0
- KratosMultiphysics/OptimizationApplication/optimizer.py +61 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_ascii_output_process.py +212 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_field_output_process.py +122 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_graph_output_process.py +184 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_hdf5_output_process.py +84 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_vtu_output_process.py +94 -0
- KratosMultiphysics/OptimizationApplication/processes/spatial_statistics_computation_process.py +81 -0
- KratosMultiphysics/OptimizationApplication/responses/__init__.py +0 -0
- KratosMultiphysics/OptimizationApplication/responses/additive_manufacturing_responses.py +410 -0
- KratosMultiphysics/OptimizationApplication/responses/analysis_based_response_function_factory.py +14 -0
- KratosMultiphysics/OptimizationApplication/responses/analysis_free_response_function_factory.py +14 -0
- KratosMultiphysics/OptimizationApplication/responses/base_response.py +66 -0
- KratosMultiphysics/OptimizationApplication/responses/binary_operator_response_function.py +103 -0
- KratosMultiphysics/OptimizationApplication/responses/combined_response_function.py +127 -0
- KratosMultiphysics/OptimizationApplication/responses/discrete_value_residual_response_function.py +131 -0
- KratosMultiphysics/OptimizationApplication/responses/evaluation_response_function.py +68 -0
- KratosMultiphysics/OptimizationApplication/responses/external_response_function.py +87 -0
- KratosMultiphysics/OptimizationApplication/responses/geometric_centroid_deviation_response_function.py +97 -0
- KratosMultiphysics/OptimizationApplication/responses/linear_strain_energy_response_function.py +72 -0
- KratosMultiphysics/OptimizationApplication/responses/literal_value_response_function.py +33 -0
- KratosMultiphysics/OptimizationApplication/responses/log_response_function.py +47 -0
- KratosMultiphysics/OptimizationApplication/responses/mass_response_function.py +71 -0
- KratosMultiphysics/OptimizationApplication/responses/response_function.py +126 -0
- KratosMultiphysics/OptimizationApplication/responses/response_routine.py +158 -0
- KratosMultiphysics/OptimizationApplication/responses/structural_responses.py +335 -0
- KratosMultiphysics/OptimizationApplication/responses_controller.py +390 -0
- KratosMultiphysics/OptimizationApplication/utilities/buffered_dict.py +399 -0
- KratosMultiphysics/OptimizationApplication/utilities/component_data_view.py +74 -0
- KratosMultiphysics/OptimizationApplication/utilities/helper_utilities.py +40 -0
- KratosMultiphysics/OptimizationApplication/utilities/logger_utilities.py +222 -0
- KratosMultiphysics/OptimizationApplication/utilities/model_part_utilities.py +117 -0
- KratosMultiphysics/OptimizationApplication/utilities/opt_line_search.py +173 -0
- KratosMultiphysics/OptimizationApplication/utilities/opt_projection.py +191 -0
- KratosMultiphysics/OptimizationApplication/utilities/optimization_problem.py +237 -0
- KratosMultiphysics/OptimizationApplication/utilities/optimization_problem_utilities.py +237 -0
- KratosMultiphysics/OptimizationApplication/utilities/response_utilities.py +249 -0
- KratosMultiphysics/OptimizationApplication/utilities/timer.py +45 -0
- KratosMultiphysics/OptimizationApplication/utilities/union_utilities.py +6 -0
- kratosoptimizationapplication-10.4.4.dist-info/METADATA +25 -0
- kratosoptimizationapplication-10.4.4.dist-info/RECORD +106 -0
- kratosoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
- kratosoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
- kratosoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
- kratosoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
- kratosoptimizationapplication.dylibs/libstdc++.6.dylib +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
class BufferedDict:
|
|
5
|
+
"""Buffered dict container with buffered data ability
|
|
6
|
+
|
|
7
|
+
Instances of this can hold (str, Any) data pairs in hierachychal data
|
|
8
|
+
structure where each sub item can have their own buffer sizes. Hence,
|
|
9
|
+
Different sub structures can have their own buffers and can be advanced
|
|
10
|
+
separately or all together.
|
|
11
|
+
|
|
12
|
+
Overwriting of the existing data is not allowed because, this is used
|
|
13
|
+
as a central place to store data from various objects, hence allowing
|
|
14
|
+
overwriting will make difficult to track the changes.
|
|
15
|
+
|
|
16
|
+
Buffer size setting can only be done at the construction time
|
|
17
|
+
of the instance to not to allow re sizing because then it is not
|
|
18
|
+
clear how to handle the connected steps.
|
|
19
|
+
|
|
20
|
+
The buffered data is stored in a cyclic buffer.
|
|
21
|
+
"""
|
|
22
|
+
def __init__(self, buffer_size: int = 1, clear_buffer_when_advancing: bool = True):
|
|
23
|
+
"""Creates an instance of BufferedDict with specified buffer size
|
|
24
|
+
|
|
25
|
+
This creates an instance of buffered data with given buffer size.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
buffer_size (int, optional): Cyclic buffer size. Defaults to 1.
|
|
29
|
+
clear_buffer_when_advancing (bool): Clears the buffer and sub item buffers when advancing.
|
|
30
|
+
"""
|
|
31
|
+
self.__parent = None
|
|
32
|
+
self.__buffer_index = 0
|
|
33
|
+
self.__buffered_data: 'list[dict[str, Any]]' = []
|
|
34
|
+
self.__sub_items: 'dict[str, BufferedDict]' = {}
|
|
35
|
+
self.__clear_buffer_when_advancing = clear_buffer_when_advancing
|
|
36
|
+
|
|
37
|
+
# sets the buffer
|
|
38
|
+
self.__SetBufferSize(buffer_size)
|
|
39
|
+
|
|
40
|
+
def GetBufferSize(self) -> int:
|
|
41
|
+
"""Returns the buffer size of current instance of buffered data
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
int: Buffer size of the cyclic buffer
|
|
45
|
+
"""
|
|
46
|
+
return len(self.__buffered_data)
|
|
47
|
+
|
|
48
|
+
def AdvanceStep(self, recursive = True) -> None:
|
|
49
|
+
"""Advances the buffered data containers
|
|
50
|
+
|
|
51
|
+
Advances to the next index of the buffer in the cyclic buffer
|
|
52
|
+
making the current index accessible as a past value index (step_index = 1)
|
|
53
|
+
|
|
54
|
+
Clears the values in the current step after advancement.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
recursive (bool, optional): Advance step recursively in sub items. Defaults to True.
|
|
58
|
+
"""
|
|
59
|
+
# first advance the current instance
|
|
60
|
+
self.__buffer_index = (self.__buffer_index + 1) % self.GetBufferSize()
|
|
61
|
+
if self.__clear_buffer_when_advancing:
|
|
62
|
+
self.__buffered_data[self.__GetBufferIndex(0)] = {}
|
|
63
|
+
|
|
64
|
+
if recursive:
|
|
65
|
+
# now advance the sub items
|
|
66
|
+
for sub_item in self.__sub_items.values():
|
|
67
|
+
sub_item.AdvanceStep(recursive)
|
|
68
|
+
|
|
69
|
+
def HasValue(self, key: str, step_index: int = 0) -> bool:
|
|
70
|
+
"""Checks whether key exists in the given step_index
|
|
71
|
+
|
|
72
|
+
The key in here should always be relative to the instance it is called upon.
|
|
73
|
+
Hence, this key can have "/" separations for subitems, then this method
|
|
74
|
+
will navigate through the sub items as well to check whether given key is available.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
key (str): Relative path of the key to be checked for.
|
|
78
|
+
step_index (int, optional): Step index to be looked for. Defaults to 0.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
bool: True if the key is found in given step index. False otherwise.
|
|
82
|
+
"""
|
|
83
|
+
pos = key.find("/")
|
|
84
|
+
|
|
85
|
+
if pos == -1:
|
|
86
|
+
# this is a leaf key, then look for the value
|
|
87
|
+
# first in the value container
|
|
88
|
+
if step_index < self.GetBufferSize() and step_index >= 0:
|
|
89
|
+
if key in self.__buffered_data[self.__GetBufferIndex(step_index)].keys():
|
|
90
|
+
return True
|
|
91
|
+
# now if it was not in the buffered data, then check it in sub items.
|
|
92
|
+
return key in self.__sub_items.keys()
|
|
93
|
+
else:
|
|
94
|
+
# not the leaf key. hence check for the sub items
|
|
95
|
+
current_key = key[:pos]
|
|
96
|
+
if current_key in self.__sub_items.keys():
|
|
97
|
+
# found the subkey. Call HasValue recursively
|
|
98
|
+
return self.__sub_items[current_key].HasValue(key[pos+1:], step_index)
|
|
99
|
+
else:
|
|
100
|
+
# not found the subkey. Hence the given key is not available.
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
def GetValue(self, key: str, step_index: int = 0) -> Any:
|
|
104
|
+
"""Get the value given by the key at the specified step_index.
|
|
105
|
+
|
|
106
|
+
This method retrieves the value given by the key at the specified step_index.
|
|
107
|
+
The key must be the relative path w.r.t. current instance of the BufferedDict.
|
|
108
|
+
It can include "/" separators to get a value which is in sub items. In this case,
|
|
109
|
+
it will be retrieved by recursive calls.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
key (str): Relative path to the value.
|
|
113
|
+
step_index (int, optional): Step index the value should be retrieved. Defaults to 0.
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
RuntimeError: If the given key is not found.
|
|
117
|
+
RuntimeError: If parent keys are not found.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Any: Value stored at the key for the specified step_index.
|
|
121
|
+
"""
|
|
122
|
+
pos = key.find("/")
|
|
123
|
+
|
|
124
|
+
if pos == -1:
|
|
125
|
+
# this is a leaf key, then look for the value
|
|
126
|
+
if not self.HasValue(key, step_index):
|
|
127
|
+
raise RuntimeError(f"The key \"{key}\" not found in the buffered data [ step_index = {step_index} ]. BufferedDict:\n{self}")
|
|
128
|
+
|
|
129
|
+
# first in the value container
|
|
130
|
+
if step_index < self.GetBufferSize() and step_index >= 0:
|
|
131
|
+
buffer_data = self.__buffered_data[self.__GetBufferIndex(step_index)]
|
|
132
|
+
if key in buffer_data.keys():
|
|
133
|
+
return buffer_data[key]
|
|
134
|
+
|
|
135
|
+
# now if it was not in the buffered data, then it is in sub items.
|
|
136
|
+
return self.__sub_items[key]
|
|
137
|
+
else:
|
|
138
|
+
current_key = key[:pos]
|
|
139
|
+
if current_key in self.__sub_items.keys():
|
|
140
|
+
return self.__sub_items[current_key].GetValue(key[pos+1:], step_index)
|
|
141
|
+
else:
|
|
142
|
+
raise RuntimeError(f"The key \"{current_key}\" not found in the buffered data which is a parent key for \"{key}\". BufferedDict:\n{self}")
|
|
143
|
+
|
|
144
|
+
def SetValue(self, key: str, value: Any, step_index: int = 0, overwrite: bool = False) -> None:
|
|
145
|
+
"""Sets a value for specified key at specified step_index.
|
|
146
|
+
|
|
147
|
+
This method sets the value at the key at the specified step_index.
|
|
148
|
+
The key must be the relative path w.r.t. current instance of the BufferedDict.
|
|
149
|
+
It can include "/" separators to set a value which is in sub items. In this case,
|
|
150
|
+
it will be set by recursive calls.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
key (str): Relative path to the value.
|
|
154
|
+
value (Any): value to be set
|
|
155
|
+
step_index (int, optional): Step index the value should be set. Defaults to 0.
|
|
156
|
+
overwrite (bool): Overwrites if existing key is found with the new value, otherwise creates a key with the value.
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
RuntimeError: If a value is overwritten.
|
|
160
|
+
"""
|
|
161
|
+
pos = key.find("/")
|
|
162
|
+
if pos == -1:
|
|
163
|
+
# this is a leaf, then we check the type of the value and add appropriately
|
|
164
|
+
if isinstance(value, dict):
|
|
165
|
+
# if the given value is a dict, then convert the structure
|
|
166
|
+
# to BufferedDict while keeping the sub_item structure.
|
|
167
|
+
sub_item = BufferedDict(self.GetBufferSize(), self.__clear_buffer_when_advancing)
|
|
168
|
+
self.__AddSubItem(key, sub_item)
|
|
169
|
+
|
|
170
|
+
# now iterate through all the sub_keys and values of the dictionary and
|
|
171
|
+
# add them to sub_item
|
|
172
|
+
for sub_key, sub_value in value.items():
|
|
173
|
+
sub_item.SetValue(f"{sub_key}", sub_value, step_index)
|
|
174
|
+
elif isinstance(value, BufferedDict):
|
|
175
|
+
# if the given value is of type BufferedDict, then put it to sub_items.
|
|
176
|
+
self.__AddSubItem(key, value)
|
|
177
|
+
else:
|
|
178
|
+
# if not any of the above, it is a normal value. Then put it to buffer.
|
|
179
|
+
self.__AddBufferedValue(key, value, step_index, overwrite)
|
|
180
|
+
else:
|
|
181
|
+
# if it is not a leaf key. then look for the sub_item, and recursively
|
|
182
|
+
# call the Set method.
|
|
183
|
+
current_key = key[:pos]
|
|
184
|
+
if not current_key in self.__sub_items.keys():
|
|
185
|
+
# no existing key found then create it.
|
|
186
|
+
self.__AddSubItem(current_key, BufferedDict(self.GetBufferSize(), self.__clear_buffer_when_advancing))
|
|
187
|
+
|
|
188
|
+
self.__sub_items[current_key].SetValue(key[pos+1:], value, step_index, overwrite)
|
|
189
|
+
|
|
190
|
+
def RemoveValue(self, key: str, step_index: int = 0) -> None:
|
|
191
|
+
"""Remove value at the key in the specified step_index
|
|
192
|
+
|
|
193
|
+
This method removes value at the key specified at the step_index.
|
|
194
|
+
The key must be the relative path w.r.t. current instance of the BufferedDict.
|
|
195
|
+
It can include "/" separators to remove a value which is in sub items. In this case,
|
|
196
|
+
it will be removed by recursive calls.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
key (str): Relative path to the value.
|
|
200
|
+
step_index (int, optional): Step index the value should be removed from. Defaults to 0.
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
RuntimeError: If the given key is not found.
|
|
204
|
+
RuntimeError: If the given parents of the key is not found.
|
|
205
|
+
"""
|
|
206
|
+
pos = key.find("/")
|
|
207
|
+
if pos == -1:
|
|
208
|
+
# found a leaf key.
|
|
209
|
+
is_reomved = False
|
|
210
|
+
|
|
211
|
+
if step_index < self.GetBufferSize() and step_index >= 0:
|
|
212
|
+
buffer_data = self.__buffered_data[self.__GetBufferIndex(step_index)]
|
|
213
|
+
# check whether the key is available in the given step_index
|
|
214
|
+
if key in buffer_data.keys():
|
|
215
|
+
is_reomved = True
|
|
216
|
+
del buffer_data[key]
|
|
217
|
+
|
|
218
|
+
if not is_reomved:
|
|
219
|
+
# if it is not removed from the buffered data, then check whether it is available
|
|
220
|
+
# in the sub_items
|
|
221
|
+
if key in self.__sub_items.keys():
|
|
222
|
+
is_reomved = True
|
|
223
|
+
del self.__sub_items[key]
|
|
224
|
+
|
|
225
|
+
if not is_reomved:
|
|
226
|
+
raise RuntimeError(f"\"{key}\" is not found. BufferedDict:\n{self}")
|
|
227
|
+
else:
|
|
228
|
+
# it is not a leaf key
|
|
229
|
+
current_key = key[:pos]
|
|
230
|
+
if current_key in self.__sub_items.keys():
|
|
231
|
+
# call recursively the sub_items remove value
|
|
232
|
+
self.__sub_items[current_key].RemoveValue(key[pos+1:], step_index)
|
|
233
|
+
else:
|
|
234
|
+
raise RuntimeError(f"\"{key}\" is not found. BufferedDict:\n{self}")
|
|
235
|
+
|
|
236
|
+
def GetValueItems(self, step_index: int = 0) -> 'dict[str, Any]':
|
|
237
|
+
return self.__buffered_data[self.__GetBufferIndex(step_index)]
|
|
238
|
+
|
|
239
|
+
def GetSubItems(self) -> 'dict[str, BufferedDict]':
|
|
240
|
+
return self.__sub_items
|
|
241
|
+
|
|
242
|
+
def GetMap(self, step_index: int = 0) -> 'dict[str, Any]':
|
|
243
|
+
"""Generates (str, Any) pair map with recursively collecting all items in the BufferedDict
|
|
244
|
+
|
|
245
|
+
This method recursively collects all items in the buffered data and returns a dict
|
|
246
|
+
with (str, Any) pairs. All the sub_items are also added as (str, BufferedDict) pairs.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
step_index (int, optional): Step index the value should be looked at. Defaults to 0.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
dict[str, Any]: (str, Any) map of all the items.
|
|
253
|
+
"""
|
|
254
|
+
key_value_pair_map = {}
|
|
255
|
+
self.__AddKeyValuePairsToMap("", key_value_pair_map, step_index)
|
|
256
|
+
return key_value_pair_map
|
|
257
|
+
|
|
258
|
+
def GetParent(self) -> BufferedDict:
|
|
259
|
+
"""Get the parent of the current buffered data
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
BufferedDict: Returns parent of the current instance.
|
|
263
|
+
"""
|
|
264
|
+
return self.__parent
|
|
265
|
+
|
|
266
|
+
def GetRoot(self) -> BufferedDict:
|
|
267
|
+
"""Get the root parent of the current buffered data
|
|
268
|
+
|
|
269
|
+
Get the root parent of the current buffered data by recursive calls.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
BufferedDict: Root parent of the current buffered data.
|
|
273
|
+
"""
|
|
274
|
+
if self.GetParent() is not None:
|
|
275
|
+
return self.GetParent().GetRoot()
|
|
276
|
+
else:
|
|
277
|
+
return self
|
|
278
|
+
|
|
279
|
+
def PrintData(self, step_index: int = -1, tabbing = "") -> str:
|
|
280
|
+
"""Prints containing data in a json like structure.
|
|
281
|
+
|
|
282
|
+
This method prints containing data and sub_item data recursively.
|
|
283
|
+
|
|
284
|
+
If the step_index == -1 then, it prints all the values on all the steps of the buffer
|
|
285
|
+
in current and all the sub_items recursively.
|
|
286
|
+
|
|
287
|
+
If the step_index > 0 then, it will only print values at that specified buffer index for
|
|
288
|
+
current instance as well as all the sub_items.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
step_index (int, optional): Step index to be printed. Defaults to -1.
|
|
292
|
+
tabbing (str, optional): Initial tabbing for json output.. Defaults to "".
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
str: String will all the containing values formatted like json.
|
|
296
|
+
"""
|
|
297
|
+
info = self.__Info(step_index, tabbing)
|
|
298
|
+
info = f"{tabbing}{info}"
|
|
299
|
+
return info
|
|
300
|
+
|
|
301
|
+
def __AddKeyValuePairsToMap(self, current_path: str, key_value_pair_map: 'dict[str, Any]', step_index: int) -> None:
|
|
302
|
+
# first add the buffered data
|
|
303
|
+
if step_index >= 0 and step_index < self.GetBufferSize():
|
|
304
|
+
buffer_data = self.__buffered_data[self.__GetBufferIndex(step_index)]
|
|
305
|
+
for k, v in buffer_data.items():
|
|
306
|
+
key_value_pair_map[f"{current_path}{k}"] = v
|
|
307
|
+
|
|
308
|
+
# now add the sub item data recursively
|
|
309
|
+
for k, v in self.__sub_items.items():
|
|
310
|
+
key_value_pair_map[f"{current_path}{k}"] = v
|
|
311
|
+
v.__AddKeyValuePairsToMap(f"{current_path}{k}/", key_value_pair_map, step_index)
|
|
312
|
+
|
|
313
|
+
def __AddBufferedValue(self, key: str, value: Any, step_index: int, overwrite: bool) -> None:
|
|
314
|
+
# first check whether this key exists in the specified step_index
|
|
315
|
+
buffer_data = self.__buffered_data[self.__GetBufferIndex(step_index)]
|
|
316
|
+
if not overwrite and key in buffer_data.keys():
|
|
317
|
+
raise RuntimeError(f"Trying to add a buffer value with key = \"{key}\" when already value exists for the key [ Existing value = {buffer_data[key]}]. BufferedDict:\n{self}")
|
|
318
|
+
|
|
319
|
+
# now check whether a sub item exists
|
|
320
|
+
if key in self.__sub_items.keys():
|
|
321
|
+
raise RuntimeError(f"Trying to add a buffer value with key = \"{key}\" when a subitem exists with the same key. BufferedDict:\n{self}")
|
|
322
|
+
|
|
323
|
+
# now add the buffer value
|
|
324
|
+
buffer_data[key] = value
|
|
325
|
+
|
|
326
|
+
def __AddSubItem(self, key: str, value: BufferedDict) -> None:
|
|
327
|
+
# first check if any of the buffered data has the same key.
|
|
328
|
+
# this is because, sub_items are valid for all step_indices.
|
|
329
|
+
if any([key in buffer_data.keys() for buffer_data in self.__buffered_data]):
|
|
330
|
+
raise RuntimeError(f"Trying to add a new a sub item with key = \"{key}\" when a value with the same key exists in buffered data. BufferedDict:\n{self}")
|
|
331
|
+
|
|
332
|
+
# now check if the item exists in the sub_items
|
|
333
|
+
if key in self.__sub_items.keys():
|
|
334
|
+
raise RuntimeError(f"Trying to add a new sub_item with key = \"{key}\" when already a sub item exists. BufferedDict:\n{self}")
|
|
335
|
+
|
|
336
|
+
# now add the sub_item
|
|
337
|
+
value.__parent = self
|
|
338
|
+
self.__sub_items[key] = value
|
|
339
|
+
|
|
340
|
+
def __SetBufferSize(self, buffer_size: int) -> None:
|
|
341
|
+
self.__buffer_index = 0
|
|
342
|
+
self.__buffered_data.clear()
|
|
343
|
+
for _ in range(buffer_size):
|
|
344
|
+
self.__buffered_data.append({})
|
|
345
|
+
|
|
346
|
+
def __GetBufferIndex(self, step_index: int) -> int:
|
|
347
|
+
if step_index >= self.GetBufferSize() or step_index < 0:
|
|
348
|
+
raise RuntimeError(f"Invalid step index. Allowed step indices are in [0, {self.GetBufferSize()}) [ StepIndex = {step_index} ]. BufferedDict:\n{self}")
|
|
349
|
+
|
|
350
|
+
return (self.__buffer_index - step_index) % self.GetBufferSize()
|
|
351
|
+
|
|
352
|
+
def __Info(self, step_index: int, tabbing: str) -> str:
|
|
353
|
+
info = "{"
|
|
354
|
+
|
|
355
|
+
if step_index == -1:
|
|
356
|
+
for i in range(self.GetBufferSize()):
|
|
357
|
+
info += f"\n{tabbing}\t--- Step = {i:2d} ---"
|
|
358
|
+
for key, value in self.__buffered_data[self.__GetBufferIndex(i)].items():
|
|
359
|
+
info += f"\n{tabbing}\t\"{key}\": {value}"
|
|
360
|
+
else:
|
|
361
|
+
for key, value in self.__buffered_data[self.__GetBufferIndex(step_index)].items():
|
|
362
|
+
info += f"\n{tabbing}\t\"{key}\": {value}"
|
|
363
|
+
|
|
364
|
+
if step_index == -1:
|
|
365
|
+
info += f"\n{tabbing}\t--- Sub items ---"
|
|
366
|
+
|
|
367
|
+
next_tabbing = f"{tabbing}\t"
|
|
368
|
+
for sub_key, sub_value in self.__sub_items.items():
|
|
369
|
+
info += f"\n{tabbing}\t\"{sub_key}\": {sub_value.__Info(step_index, next_tabbing)}"
|
|
370
|
+
|
|
371
|
+
info += f"\n{tabbing}" + "}"
|
|
372
|
+
return info
|
|
373
|
+
|
|
374
|
+
def __getitem__(self, key: str) -> Any:
|
|
375
|
+
if isinstance(key, str):
|
|
376
|
+
return self.GetValue(key)
|
|
377
|
+
elif isinstance(key, tuple) and len(key) == 2:
|
|
378
|
+
return self.GetValue(key[0], key[1])
|
|
379
|
+
else:
|
|
380
|
+
raise RuntimeError(f"The key should be either a string (representing the key path) or (string, int) tuple (representing key path and step index) [ key = {key}].")
|
|
381
|
+
|
|
382
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
383
|
+
if isinstance(key, str):
|
|
384
|
+
return self.SetValue(key, value)
|
|
385
|
+
elif isinstance(key, tuple) and len(key) == 2:
|
|
386
|
+
return self.SetValue(key[0], value, key[1])
|
|
387
|
+
else:
|
|
388
|
+
raise RuntimeError(f"The key should be either a string (representing the key path) or (string, int) tuple (representing key path and step index) [ key = {key}].")
|
|
389
|
+
|
|
390
|
+
def __delitem__(self, key: str) -> None:
|
|
391
|
+
if isinstance(key, str):
|
|
392
|
+
return self.RemoveValue(key)
|
|
393
|
+
elif isinstance(key, tuple) and len(key) == 2:
|
|
394
|
+
return self.RemoveValue(key[0], key[1])
|
|
395
|
+
else:
|
|
396
|
+
raise RuntimeError(f"The key should be either a string (representing the key path) or (string, int) tuple (representing key path and step index) [ key = {key}].")
|
|
397
|
+
|
|
398
|
+
def __str__(self) -> str:
|
|
399
|
+
return self.__Info(-1, "")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from KratosMultiphysics.OptimizationApplication.utilities.buffered_dict import BufferedDict
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
4
|
+
|
|
5
|
+
class ComponentDataView:
|
|
6
|
+
"""A viewer to view component's data in optimization problem.
|
|
7
|
+
|
|
8
|
+
Instances of this class create or view provided component's data in
|
|
9
|
+
the OptimizationProblem container. It will view both buffered and
|
|
10
|
+
unbuffered data.
|
|
11
|
+
|
|
12
|
+
The component must be first added to the OptimizationProblem
|
|
13
|
+
to use instances of this class to modify component data.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, component: Any, optimization_problem: OptimizationProblem):
|
|
17
|
+
self.__problem_data = optimization_problem.GetProblemDataContainer()
|
|
18
|
+
|
|
19
|
+
if isinstance(component, str):
|
|
20
|
+
self.__component_type = object
|
|
21
|
+
self.__component_name = component
|
|
22
|
+
else:
|
|
23
|
+
self.__component_type = optimization_problem.GetComponentType(component)
|
|
24
|
+
self.__component_name = optimization_problem.GetComponentName(component)
|
|
25
|
+
|
|
26
|
+
self.__data_name = f"{self.__component_type.__name__}/{self.__component_name}"
|
|
27
|
+
self.__buffered_data_name = f"{self.__data_name}/buffered"
|
|
28
|
+
self.__unbuffered_data_name = f"{self.__data_name}/unbuffered"
|
|
29
|
+
self.__component = component
|
|
30
|
+
|
|
31
|
+
# if the component data container not found, then create it.
|
|
32
|
+
if not self.__problem_data.HasValue(self.__data_name):
|
|
33
|
+
self.ResetData()
|
|
34
|
+
|
|
35
|
+
def ResetData(self):
|
|
36
|
+
if self.__problem_data.HasValue(self.__data_name):
|
|
37
|
+
# if exists, delete the current problem data
|
|
38
|
+
del self.__problem_data[self.__data_name]
|
|
39
|
+
|
|
40
|
+
self.__problem_data[self.__data_name] = BufferedDict(1)
|
|
41
|
+
# create the unbuffered data container
|
|
42
|
+
self.__problem_data[self.__unbuffered_data_name] = BufferedDict(1, False)
|
|
43
|
+
|
|
44
|
+
def SetDataBuffer(self, buffer_size: int):
|
|
45
|
+
if not self.__problem_data.HasValue(self.__buffered_data_name):
|
|
46
|
+
self.__problem_data[self.__buffered_data_name] = BufferedDict(buffer_size)
|
|
47
|
+
else:
|
|
48
|
+
buffered_data: BufferedDict = self.__problem_data[self.__buffered_data_name]
|
|
49
|
+
if buffered_data.GetBufferSize() < buffer_size:
|
|
50
|
+
raise RuntimeError(f"The required buffer size is not satisfied with the existing problem data container. [ component data container buffer size = {buffered_data.GetBufferSize()}, required buffer size = {buffer_size}, component = {self.__component_name}, component type = {self.__component_type}")
|
|
51
|
+
|
|
52
|
+
def HasDataBuffer(self) -> bool:
|
|
53
|
+
return self.__problem_data.HasValue(self.__buffered_data_name)
|
|
54
|
+
|
|
55
|
+
def GetComponent(self) -> Any:
|
|
56
|
+
return self.__component
|
|
57
|
+
|
|
58
|
+
def GetBufferedData(self) -> BufferedDict:
|
|
59
|
+
if not self.HasDataBuffer():
|
|
60
|
+
raise RuntimeError(f"Buffered data is not set by calling ComponentData::SetDataBuffer for component of type \"{self.__component_type}\" with component name \"{self.__component_name}\".")
|
|
61
|
+
|
|
62
|
+
return self.__problem_data[self.__buffered_data_name]
|
|
63
|
+
|
|
64
|
+
def GetUnBufferedData(self) -> BufferedDict:
|
|
65
|
+
return self.__problem_data[self.__unbuffered_data_name]
|
|
66
|
+
|
|
67
|
+
def GetDataPath(self) -> str:
|
|
68
|
+
return self.__data_name
|
|
69
|
+
|
|
70
|
+
def GetComponentName(self):
|
|
71
|
+
if isinstance(self.__component, str):
|
|
72
|
+
return self.__component
|
|
73
|
+
else:
|
|
74
|
+
return self.__component.GetName()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import KratosMultiphysics as Kratos
|
|
5
|
+
from KratosMultiphysics.kratos_utilities import GetListOfAvailableApplications
|
|
6
|
+
from KratosMultiphysics.kratos_utilities import GetKratosMultiphysicsPath
|
|
7
|
+
|
|
8
|
+
def GetClassModuleFromKratos(full_class_name: str) -> str:
|
|
9
|
+
sub_module_paths = full_class_name.split(".")
|
|
10
|
+
|
|
11
|
+
if not sub_module_paths:
|
|
12
|
+
raise RuntimeError("Empty class names are not allowed.")
|
|
13
|
+
|
|
14
|
+
relative_sub_module = Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(sub_module_paths[-1])
|
|
15
|
+
if len(sub_module_paths) > 1:
|
|
16
|
+
relative_sub_module = ".".join(sub_module_paths[:-1]) + f".{relative_sub_module}"
|
|
17
|
+
|
|
18
|
+
relative_sub_module_path = relative_sub_module.replace(".", "/")
|
|
19
|
+
kratos_path = GetKratosMultiphysicsPath()
|
|
20
|
+
|
|
21
|
+
# check whether it is in Kratos core
|
|
22
|
+
if Path(f"{kratos_path}/{relative_sub_module_path}.py").is_file():
|
|
23
|
+
return f"KratosMultiphysics.{relative_sub_module}", sub_module_paths[-1]
|
|
24
|
+
|
|
25
|
+
# now check if it is found in any of the compiled applications
|
|
26
|
+
list_of_available_appliacations = GetListOfAvailableApplications()
|
|
27
|
+
|
|
28
|
+
module_application = ""
|
|
29
|
+
for application in list_of_available_appliacations:
|
|
30
|
+
if Path(f"{kratos_path}/{application}/{relative_sub_module_path}.py").is_file():
|
|
31
|
+
module_application = f"KratosMultiphysics.{application}.{relative_sub_module}"
|
|
32
|
+
|
|
33
|
+
if module_application != "":
|
|
34
|
+
return module_application, sub_module_paths[-1]
|
|
35
|
+
else:
|
|
36
|
+
raise RuntimeError(f"{full_class_name} is not found in KratosMultiphysics core or any of the available application directories in Kratos. Available applications:\n\t" + "\n\t".join(list_of_available_appliacations))
|
|
37
|
+
|
|
38
|
+
def CallOnAll(list_of_objects: 'list[Any]', method: Any, *args, **kwargs):
|
|
39
|
+
for obj in list_of_objects:
|
|
40
|
+
getattr(obj, method.__name__)(*args, **kwargs)
|