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.
Files changed (106) hide show
  1. KratosMultiphysics/.libs/KratosOptimizationApplication.so +0 -0
  2. KratosMultiphysics/.libs/libKratosOptimizationCore.dylib +0 -0
  3. KratosMultiphysics/OptimizationApplication/__init__.py +19 -0
  4. KratosMultiphysics/OptimizationApplication/algorithms/NLOPT_algorithms.py +255 -0
  5. KratosMultiphysics/OptimizationApplication/algorithms/SciPy_algorithms.py +154 -0
  6. KratosMultiphysics/OptimizationApplication/algorithms/__init__.py +0 -0
  7. KratosMultiphysics/OptimizationApplication/algorithms/algorithm.py +78 -0
  8. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_adam.py +68 -0
  9. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_base.py +393 -0
  10. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_gradient_projection.py +355 -0
  11. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_momentum_relaxed_gradient_projection.py +70 -0
  12. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_nesterov_accelarated_gradient.py +60 -0
  13. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +263 -0
  14. KratosMultiphysics/OptimizationApplication/algorithms/algorithm_steepest_descent.py +205 -0
  15. KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_constraint.py +194 -0
  16. KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_objective.py +191 -0
  17. KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_constraint.py +123 -0
  18. KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_objective.py +148 -0
  19. KratosMultiphysics/OptimizationApplication/algorithms/standardized_constraint.py +180 -0
  20. KratosMultiphysics/OptimizationApplication/algorithms/standardized_objective.py +133 -0
  21. KratosMultiphysics/OptimizationApplication/algorithms/standardized_rgp_constraint.py +268 -0
  22. KratosMultiphysics/OptimizationApplication/analyses_controller.py +75 -0
  23. KratosMultiphysics/OptimizationApplication/controls/control.py +123 -0
  24. KratosMultiphysics/OptimizationApplication/controls/external_response_function_control.py +149 -0
  25. KratosMultiphysics/OptimizationApplication/controls/master_control.py +198 -0
  26. KratosMultiphysics/OptimizationApplication/controls/material/material_properties_control.py +115 -0
  27. KratosMultiphysics/OptimizationApplication/controls/material/simp_control.py +229 -0
  28. KratosMultiphysics/OptimizationApplication/controls/shape/vertex_morphing_shape_control.py +289 -0
  29. KratosMultiphysics/OptimizationApplication/controls/thickness/shell_thickness_control.py +180 -0
  30. KratosMultiphysics/OptimizationApplication/controls_controller.py +205 -0
  31. KratosMultiphysics/OptimizationApplication/convergence_criteria/avg_abs_improvement_conv_criterion.py +98 -0
  32. KratosMultiphysics/OptimizationApplication/convergence_criteria/combined_conv_criterion.py +87 -0
  33. KratosMultiphysics/OptimizationApplication/convergence_criteria/constraint_conv_criterion.py +68 -0
  34. KratosMultiphysics/OptimizationApplication/convergence_criteria/convergence_criterion.py +26 -0
  35. KratosMultiphysics/OptimizationApplication/convergence_criteria/l2_conv_criterion.py +77 -0
  36. KratosMultiphysics/OptimizationApplication/convergence_criteria/magnitude_reduction_conv_criterion.py +85 -0
  37. KratosMultiphysics/OptimizationApplication/convergence_criteria/max_iter_conv_criterion.py +48 -0
  38. KratosMultiphysics/OptimizationApplication/convergence_criteria/patience_conv_criterion.py +116 -0
  39. KratosMultiphysics/OptimizationApplication/convergence_criteria/target_value_conv_criterion.py +64 -0
  40. KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy.py +46 -0
  41. KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy_decorator.py +67 -0
  42. KratosMultiphysics/OptimizationApplication/execution_policies/independent_analysis_execution_policy.py +78 -0
  43. KratosMultiphysics/OptimizationApplication/execution_policies/kratos_analysis_execution_policy.py +137 -0
  44. KratosMultiphysics/OptimizationApplication/execution_policies/stepping_analysis_execution_policy.py +88 -0
  45. KratosMultiphysics/OptimizationApplication/filtering/explicit_filter.py +124 -0
  46. KratosMultiphysics/OptimizationApplication/filtering/filter.py +188 -0
  47. KratosMultiphysics/OptimizationApplication/filtering/filter_utils.py +55 -0
  48. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_analysis.py +139 -0
  49. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_scalar_solver.py +39 -0
  50. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_shape_solver.py +67 -0
  51. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_solver_base.py +275 -0
  52. KratosMultiphysics/OptimizationApplication/filtering/helmholtz_vector_solver.py +39 -0
  53. KratosMultiphysics/OptimizationApplication/filtering/implicit_filter.py +192 -0
  54. KratosMultiphysics/OptimizationApplication/filtering/python_solvers_wrapper_implicit_filters.py +56 -0
  55. KratosMultiphysics/OptimizationApplication/model_part_controllers/connectivity_preserving_model_part_controller.py +72 -0
  56. KratosMultiphysics/OptimizationApplication/model_part_controllers/external_response_function_model_part_controller.py +110 -0
  57. KratosMultiphysics/OptimizationApplication/model_part_controllers/mdpa_model_part_controller.py +44 -0
  58. KratosMultiphysics/OptimizationApplication/model_part_controllers/model_part_controller.py +19 -0
  59. KratosMultiphysics/OptimizationApplication/model_parts_controller.py +92 -0
  60. KratosMultiphysics/OptimizationApplication/optimization_analysis.py +146 -0
  61. KratosMultiphysics/OptimizationApplication/optimizations_controller.py +223 -0
  62. KratosMultiphysics/OptimizationApplication/optimizer.py +61 -0
  63. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_ascii_output_process.py +212 -0
  64. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_field_output_process.py +122 -0
  65. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_graph_output_process.py +184 -0
  66. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_hdf5_output_process.py +84 -0
  67. KratosMultiphysics/OptimizationApplication/processes/optimization_problem_vtu_output_process.py +94 -0
  68. KratosMultiphysics/OptimizationApplication/processes/spatial_statistics_computation_process.py +81 -0
  69. KratosMultiphysics/OptimizationApplication/responses/__init__.py +0 -0
  70. KratosMultiphysics/OptimizationApplication/responses/additive_manufacturing_responses.py +410 -0
  71. KratosMultiphysics/OptimizationApplication/responses/analysis_based_response_function_factory.py +14 -0
  72. KratosMultiphysics/OptimizationApplication/responses/analysis_free_response_function_factory.py +14 -0
  73. KratosMultiphysics/OptimizationApplication/responses/base_response.py +66 -0
  74. KratosMultiphysics/OptimizationApplication/responses/binary_operator_response_function.py +103 -0
  75. KratosMultiphysics/OptimizationApplication/responses/combined_response_function.py +127 -0
  76. KratosMultiphysics/OptimizationApplication/responses/discrete_value_residual_response_function.py +131 -0
  77. KratosMultiphysics/OptimizationApplication/responses/evaluation_response_function.py +68 -0
  78. KratosMultiphysics/OptimizationApplication/responses/external_response_function.py +87 -0
  79. KratosMultiphysics/OptimizationApplication/responses/geometric_centroid_deviation_response_function.py +97 -0
  80. KratosMultiphysics/OptimizationApplication/responses/linear_strain_energy_response_function.py +72 -0
  81. KratosMultiphysics/OptimizationApplication/responses/literal_value_response_function.py +33 -0
  82. KratosMultiphysics/OptimizationApplication/responses/log_response_function.py +47 -0
  83. KratosMultiphysics/OptimizationApplication/responses/mass_response_function.py +71 -0
  84. KratosMultiphysics/OptimizationApplication/responses/response_function.py +126 -0
  85. KratosMultiphysics/OptimizationApplication/responses/response_routine.py +158 -0
  86. KratosMultiphysics/OptimizationApplication/responses/structural_responses.py +335 -0
  87. KratosMultiphysics/OptimizationApplication/responses_controller.py +390 -0
  88. KratosMultiphysics/OptimizationApplication/utilities/buffered_dict.py +399 -0
  89. KratosMultiphysics/OptimizationApplication/utilities/component_data_view.py +74 -0
  90. KratosMultiphysics/OptimizationApplication/utilities/helper_utilities.py +40 -0
  91. KratosMultiphysics/OptimizationApplication/utilities/logger_utilities.py +222 -0
  92. KratosMultiphysics/OptimizationApplication/utilities/model_part_utilities.py +117 -0
  93. KratosMultiphysics/OptimizationApplication/utilities/opt_line_search.py +173 -0
  94. KratosMultiphysics/OptimizationApplication/utilities/opt_projection.py +191 -0
  95. KratosMultiphysics/OptimizationApplication/utilities/optimization_problem.py +237 -0
  96. KratosMultiphysics/OptimizationApplication/utilities/optimization_problem_utilities.py +237 -0
  97. KratosMultiphysics/OptimizationApplication/utilities/response_utilities.py +249 -0
  98. KratosMultiphysics/OptimizationApplication/utilities/timer.py +45 -0
  99. KratosMultiphysics/OptimizationApplication/utilities/union_utilities.py +6 -0
  100. kratosoptimizationapplication-10.4.4.dist-info/METADATA +25 -0
  101. kratosoptimizationapplication-10.4.4.dist-info/RECORD +106 -0
  102. kratosoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
  103. kratosoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
  104. kratosoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
  105. kratosoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
  106. kratosoptimizationapplication.dylibs/libstdc++.6.dylib +0 -0
@@ -0,0 +1,229 @@
1
+ import typing
2
+ import numpy
3
+ import KratosMultiphysics as Kratos
4
+ import KratosMultiphysics.OptimizationApplication as KratosOA
5
+ from KratosMultiphysics.OptimizationApplication.controls.control import Control
6
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
7
+ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
8
+ from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
9
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
10
+ from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory
11
+ from KratosMultiphysics.OptimizationApplication.utilities.opt_projection import CreateProjection
12
+
13
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control:
14
+ if not parameters.Has("name"):
15
+ raise RuntimeError(f"SimpControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
16
+ if not parameters.Has("settings"):
17
+ raise RuntimeError(f"SimpControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
18
+ return SimpControl(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
19
+
20
+ class Materials:
21
+ def __init__(self, parameters: 'list[Kratos.Parameters]') -> None:
22
+ default_parameters = Kratos.Parameters("""{
23
+ "density" : 1.0,
24
+ "young_modulus": 1.0
25
+ }""")
26
+
27
+ self.__list_of_densities: 'list[float]' = []
28
+ self.__list_of_young_modulus: 'list[float]' = []
29
+ self.__phi: 'list[float]' = []
30
+
31
+ data: 'list[tuple[float, float]]' = []
32
+ for params in parameters:
33
+ params.ValidateAndAssignDefaults(default_parameters)
34
+ data.append((params["density"].GetDouble(), params["young_modulus"].GetDouble()))
35
+
36
+ # sort in ascending order of densities
37
+ data = sorted(data, key=lambda x: x[0])
38
+
39
+ # now check whether the young modulus is also arranged in the ascending order
40
+ for i, (_, young_modulus) in enumerate(data[:-1]):
41
+ if young_modulus > data[i+1][1]:
42
+ raise RuntimeError("Young modulus and densities are not in the ascending order.")
43
+
44
+ for i, (density, young_modulus) in enumerate(data):
45
+ self.__phi.append(i)
46
+ self.__list_of_densities.append(density)
47
+ self.__list_of_young_modulus.append(young_modulus)
48
+
49
+ def GetDensities(self) -> 'list[float]':
50
+ return self.__list_of_densities
51
+
52
+ def GetYoungModulus(self) -> 'list[float]':
53
+ return self.__list_of_young_modulus
54
+
55
+ def GetPhi(self) -> 'list[float]':
56
+ return self.__phi
57
+
58
+ class SimpControl(Control):
59
+ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> None:
60
+ super().__init__(name)
61
+
62
+ self.parameters = parameters
63
+ self.model = model
64
+ self.optimization_problem = optimization_problem
65
+
66
+ default_settings = Kratos.Parameters("""{
67
+ "controlled_model_part_names" : [""],
68
+ "output_all_fields" : true,
69
+ "echo_level" : 0,
70
+ "consider_recursive_property_update": false,
71
+ "density_projection_settings" : {},
72
+ "young_modulus_projection_settings" : {},
73
+ "filter_settings" : {},
74
+ "list_of_materials" : [
75
+ {
76
+ "density" : 1.0,
77
+ "young_modulus": 1.0
78
+ }
79
+ ]
80
+ }""")
81
+
82
+ parameters.ValidateAndAssignDefaults(default_settings)
83
+
84
+ self.output_all_fields = parameters["output_all_fields"].GetBool()
85
+ self.echo_level = parameters["echo_level"].GetInt()
86
+
87
+ self.controlled_physical_variables = [Kratos.DENSITY, Kratos.YOUNG_MODULUS]
88
+
89
+ self.materials = Materials(parameters["list_of_materials"].values())
90
+
91
+ self.density_projection = CreateProjection(parameters["density_projection_settings"], self.optimization_problem)
92
+ self.young_modulus_projection = CreateProjection(parameters["young_modulus_projection_settings"], self.optimization_problem)
93
+
94
+ controlled_model_names_parts = parameters["controlled_model_part_names"].GetStringArray()
95
+ if len(controlled_model_names_parts) == 0:
96
+ raise RuntimeError(f"No model parts are provided for SimpControl. [ control name = \"{self.GetName()}\"]")
97
+ self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", controlled_model_names_parts, False)
98
+ self.model_part: 'typing.Optional[Kratos.ModelPart]' = None
99
+
100
+ self.consider_recursive_property_update = parameters["consider_recursive_property_update"].GetBool()
101
+
102
+ # filtering settings
103
+ self.filter = FilterFactory(self.model, self.model_part_operation.GetModelPartFullName(), Kratos.DENSITY, Kratos.Globals.DataLocation.Element, parameters["filter_settings"])
104
+
105
+ def Initialize(self) -> None:
106
+ self.un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData()
107
+
108
+ # init model parts
109
+ self.model_part = self.model_part_operation.GetModelPart()
110
+
111
+ # Creating element specific properties for Youngs Modulus and Density
112
+ if not KratosOA.OptAppModelPartUtils.CheckModelPartStatus(self.model_part, "element_specific_properties_created"):
113
+ KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(self.model_part, self.model_part.Elements, self.consider_recursive_property_update)
114
+ KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.model_part, "element_specific_properties_created")
115
+
116
+ self.filter.SetComponentDataView(ComponentDataView(self, self.optimization_problem))
117
+ self.filter.Initialize()
118
+
119
+ # initialize the projections
120
+ self.density_projection.SetProjectionSpaces(self.materials.GetPhi(), self.materials.GetDensities())
121
+ self.young_modulus_projection.SetProjectionSpaces(self.materials.GetPhi(), self.materials.GetYoungModulus())
122
+
123
+ # check if the density or Young's modulus is defined
124
+ element: Kratos.Element
125
+ for element in self.model_part.Elements:
126
+ break
127
+ is_density_defined = element.Properties.Has(Kratos.DENSITY)
128
+ is_youngs_modulus_defined = element.Properties.Has(Kratos.YOUNG_MODULUS)
129
+ if is_density_defined:
130
+ if is_youngs_modulus_defined:
131
+ Kratos.Logger.PrintWarning(self.__class__.__name__, f"Elements of {self.model_part.FullName()} defines both DENSITY and YOUNG_MODULUS. Using DENSITY for initial field calculation and ignoring YOUNG_MODULUS.")
132
+ density = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)
133
+ density.CollectData()
134
+ self.simp_physical_phi = self.density_projection.ProjectBackward(density)
135
+ elif is_youngs_modulus_defined:
136
+ young_modulus = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.YOUNG_MODULUS)
137
+ young_modulus.CollectData()
138
+ self.simp_physical_phi = self.young_modulus_projection.ProjectBackward(young_modulus)
139
+ else:
140
+ raise RuntimeError(f"Elements of {self.model_part.FullName()} does not define either DENSITY or YOUNG_MODULUS.")
141
+
142
+ # get the control field
143
+ self.control_phi = self.filter.UnfilterField(self.simp_physical_phi)
144
+
145
+ self._UpdateAndOutputFields(self.GetEmptyField())
146
+
147
+ def Check(self) -> None:
148
+ self.filter.Check()
149
+
150
+ def Finalize(self) -> None:
151
+ self.filter.Finalize()
152
+
153
+ def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
154
+ return self.controlled_physical_variables
155
+
156
+ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
157
+ field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)
158
+ field.data[:] = 0.0
159
+ return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False)
160
+
161
+ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
162
+ return Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_phi) # returning a copy
163
+
164
+ def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
165
+ keys = physical_variable_gradient_map.keys()
166
+ if len(keys) != 2:
167
+ raise RuntimeError(f"Not provided required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
168
+ if Kratos.DENSITY not in keys or Kratos.YOUNG_MODULUS not in keys:
169
+ raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. DENSITY or YOUNG_MODULUS not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
170
+
171
+ # first calculate the density partial sensitivity of the response function
172
+ d_j_d_density = physical_variable_gradient_map[Kratos.DENSITY]
173
+
174
+ # second calculate the young modulus partial sensitivity of the response function
175
+ d_j_d_youngs = physical_variable_gradient_map[Kratos.YOUNG_MODULUS]
176
+
177
+ # now compute response function total sensitivity w.r.t. phi
178
+ d_j_d_phi = Kratos.TensorAdaptors.DoubleTensorAdaptor(d_j_d_density)
179
+ d_j_d_phi.data = d_j_d_density.data * self.d_density_d_phi.data + d_j_d_youngs.data * self.d_young_modulus_d_phi.data
180
+
181
+ return self.filter.BackwardFilterIntegratedField(d_j_d_phi)
182
+
183
+ def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
184
+ if control_field.GetContainer() != self.model_part.Elements:
185
+ raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
186
+
187
+ update = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_field)
188
+ update.data = control_field.data - self.control_phi.data
189
+ if numpy.linalg.norm(update.data) > 1e-15:
190
+ self.control_phi.data[:] = control_field.data[:]
191
+ self._UpdateAndOutputFields(update)
192
+ self.density_projection.Update()
193
+ self.young_modulus_projection.Update()
194
+ return True
195
+
196
+ self.density_projection.Update()
197
+ self.young_modulus_projection.Update()
198
+ return False
199
+
200
+ def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
201
+ # filter the control field
202
+ physical_phi_update = self.filter.ForwardFilterField(update)
203
+ self.simp_physical_phi.data += physical_phi_update.data
204
+
205
+ density = self.density_projection.ProjectForward(self.simp_physical_phi)
206
+ KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(density, Kratos.DENSITY, copy=False).StoreData()
207
+ if self.consider_recursive_property_update:
208
+ KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(density.GetContainer(), Kratos.DENSITY)
209
+ self.un_buffered_data.SetValue("DENSITY", density, overwrite=True)
210
+
211
+ youngs_modulus = self.young_modulus_projection.ProjectForward(self.simp_physical_phi)
212
+ KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(youngs_modulus, Kratos.YOUNG_MODULUS, copy=False).StoreData()
213
+ if self.consider_recursive_property_update:
214
+ KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(youngs_modulus.GetContainer(), Kratos.YOUNG_MODULUS)
215
+ self.un_buffered_data.SetValue("YOUNG_MODULUS", youngs_modulus, overwrite=True)
216
+
217
+ # now calculate the total sensitivities of density w.r.t. phi
218
+ self.d_density_d_phi = self.density_projection.ForwardProjectionGradient(self.simp_physical_phi)
219
+
220
+ # now calculate the total sensitivities of young modulus w.r.t. simp_physical_phi
221
+ self.d_young_modulus_d_phi = self.young_modulus_projection.ForwardProjectionGradient(self.simp_physical_phi)
222
+
223
+ # now output the fields
224
+ un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData()
225
+ un_buffered_data.SetValue(f"{self.GetName()}", self.simp_physical_phi.Clone(),overwrite=True)
226
+ if self.output_all_fields:
227
+ un_buffered_data.SetValue(f"{self.GetName()}_update", physical_phi_update, overwrite=True)
228
+ un_buffered_data.SetValue(f"dDENSITY_d{self.GetName()}", self.d_density_d_phi.Clone(), overwrite=True)
229
+ un_buffered_data.SetValue(f"dYOUNG_MODULUS_d{self.GetName()}", self.d_young_modulus_d_phi.Clone(), overwrite=True)
@@ -0,0 +1,289 @@
1
+ import numpy
2
+ from typing import Optional
3
+
4
+ import KratosMultiphysics as Kratos
5
+ import KratosMultiphysics.OptimizationApplication as KratosOA
6
+ from KratosMultiphysics.OptimizationApplication.controls.control import Control
7
+ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
8
+ from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
9
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
10
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
11
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
12
+ from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory
13
+ import math
14
+
15
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control:
16
+ if not parameters.Has("name"):
17
+ raise RuntimeError(f"VertexMorphingShapeControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
18
+ if not parameters.Has("settings"):
19
+ raise RuntimeError(f"VertexMorphingShapeControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
20
+
21
+ return VertexMorphingShapeControl(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
22
+
23
+ class VertexMorphingShapeControl(Control):
24
+ """Node-based shape control using implicit and explicit Vertex Morphing techniques
25
+
26
+ This is filtering-based discrete shape control which parametrizes and controls
27
+ discrete shell and solid geometries.
28
+
29
+ """
30
+ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
31
+ super().__init__(name)
32
+
33
+ self.parameters = parameters
34
+ self.model = model
35
+ self.optimization_problem = optimization_problem
36
+
37
+ default_settings = Kratos.Parameters("""{
38
+ "controlled_model_part_names": [],
39
+ "filter_settings" : {},
40
+ "mesh_motion_solver_type" : "none",
41
+ "skin_model_part_names" : [],
42
+ "mesh_motion_solver_settings": {},
43
+ "output_all_fields" : false
44
+ }""")
45
+
46
+ self.parameters.ValidateAndAssignDefaults(default_settings)
47
+
48
+ self.output_all_fields = self.parameters["output_all_fields"].GetBool()
49
+
50
+ controlled_model_names_parts = parameters["controlled_model_part_names"].GetStringArray()
51
+ if len(controlled_model_names_parts) == 0:
52
+ raise RuntimeError(f"No model parts are provided for VertexMorphingShapeControl. [ control name = \"{self.GetName()}\"]")
53
+
54
+ self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", controlled_model_names_parts, False)
55
+ self.model_part: 'Optional[Kratos.ModelPart]' = None
56
+
57
+ self.filter = FilterFactory(self.model, self.model_part_operation.GetModelPartFullName(), KratosOA.SHAPE, Kratos.Globals.DataLocation.NodeHistorical, self.parameters["filter_settings"])
58
+
59
+ # now setup mesh motion
60
+ self.__mesh_moving_analysis: 'Optional[MeshMovingAnalysis]' = None
61
+ self.__boundary_model_part: 'Optional[Kratos.ModelPart]' = None
62
+
63
+ self.mesh_motion_solver_type = self.parameters["mesh_motion_solver_type"].GetString()
64
+ supported_mesh_motion_solver_types = ["mesh_moving_analysis", "filter_based", "none"]
65
+ if self.mesh_motion_solver_type not in supported_mesh_motion_solver_types:
66
+ raise RuntimeError(f"Unsupported mesh_motion_solver_type = \"{self.mesh_motion_solver_type}\" requested. Supported types are:\n\t" + "\n\t".join(supported_mesh_motion_solver_types))
67
+
68
+ if self.mesh_motion_solver_type == "mesh_moving_analysis":
69
+ # import is done here, so that, if it is not required to use mesh_motion,
70
+ # then it is not loaded, hence not even required to have MeshMovingApplication
71
+ # compiled.
72
+ from KratosMultiphysics.MeshMovingApplication.mesh_moving_analysis import MeshMovingAnalysis
73
+ self.__mesh_moving_analysis = MeshMovingAnalysis(self.model, self.parameters["mesh_motion_solver_settings"])
74
+
75
+ @time_decorator(methodName="GetName")
76
+ def Initialize(self) -> None:
77
+ self.model_part = self.model_part_operation.GetModelPart()
78
+
79
+ # initialize filters
80
+ self.filter.SetComponentDataView(ComponentDataView(self, self.optimization_problem))
81
+ self.filter.Initialize()
82
+
83
+ self.control_field = self.filter.UnfilterField(self.GetPhysicalField())
84
+
85
+ # initialize_mesh_motion if defined.
86
+ if not self.__mesh_moving_analysis is None:
87
+ self.__mesh_moving_analysis.Initialize()
88
+
89
+ def recursively_increase_usage(model_part: Kratos.ModelPart) -> None:
90
+ if not model_part.Has(KratosOA.NUMBER_OF_SOLVERS_USING_NODES):
91
+ model_part[KratosOA.NUMBER_OF_SOLVERS_USING_NODES] = 0
92
+ model_part[KratosOA.NUMBER_OF_SOLVERS_USING_NODES] += 1
93
+
94
+ for sub_model_part in model_part.SubModelParts:
95
+ recursively_increase_usage(sub_model_part)
96
+
97
+ # we increase the usage of all the sub-model parts because, mesh moving works with
98
+ # root model parts, and all the sub model parts are suing the root model parts. Hence
99
+ # mesh moving will affect all the shared sub-model parts
100
+ recursively_increase_usage(self.__mesh_moving_analysis._GetSolver().GetComputingModelPart())
101
+
102
+ # now update
103
+ self._UpdateAndOutputFields(self.GetEmptyField())
104
+
105
+ def Check(self) -> None:
106
+ self.filter.Check()
107
+
108
+ def Finalize(self) -> None:
109
+ self.filter.Finalize()
110
+ if not self.__mesh_moving_analysis is None:
111
+ self.__mesh_moving_analysis.Finalize()
112
+ del self.__mesh_moving_analysis
113
+
114
+ def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
115
+ return [KratosOA.SHAPE]
116
+
117
+ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
118
+ field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.__GetPhysicalModelPart().Nodes, KratosOA.SHAPE)
119
+ field.data[:] = 0.0
120
+ return field
121
+
122
+ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
123
+ return Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_field)
124
+
125
+ def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
126
+ physical_shape_field = Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.__GetPhysicalModelPart().Nodes, Kratos.Configuration.Initial)
127
+ physical_shape_field.CollectData()
128
+ return physical_shape_field
129
+
130
+ @time_decorator(methodName="GetName")
131
+ def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
132
+ keys = physical_variable_gradient_map.keys()
133
+ if len(keys) != 1:
134
+ raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
135
+ if KratosOA.SHAPE not in keys:
136
+ raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {KratosOA.SHAPE.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
137
+
138
+ physical_gradient = physical_variable_gradient_map[KratosOA.SHAPE]
139
+ if physical_gradient.GetContainer() != self.__GetPhysicalModelPart().Nodes:
140
+ raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]")
141
+
142
+ filtered_gradient = self.filter.BackwardFilterIntegratedField(self.__ExtractDesignSurfaceData(physical_gradient, self.model_part.Nodes))
143
+
144
+ return self.__ExtractDesignSurfaceData(filtered_gradient, self.__GetPhysicalModelPart().Nodes)
145
+
146
+ @time_decorator(methodName="GetName")
147
+ def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
148
+ if new_control_field.GetContainer() != self.__GetPhysicalModelPart().Nodes:
149
+ raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {new_control_field.GetModelPart().FullName()} ]")
150
+
151
+ control_update = Kratos.TensorAdaptors.DoubleTensorAdaptor(new_control_field)
152
+ control_update.data = new_control_field.data - self.control_field.data
153
+ if not math.isclose(numpy.linalg.norm(control_update.data), 0.0, abs_tol=1e-16):
154
+ # update the control SHAPE field
155
+ self.control_field.data[:] = new_control_field.data[:]
156
+ # now update the physical field
157
+ self._UpdateAndOutputFields(control_update)
158
+
159
+ self.filter.Update()
160
+ return True
161
+ return False
162
+
163
+ def _UpdateAndOutputFields(self, control_update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
164
+ # compute the shape update
165
+ if self.mesh_motion_solver_type == "filter_based":
166
+ shape_update = self.filter.ForwardFilterField(control_update)
167
+ else:
168
+ shape_update = self.filter.ForwardFilterField(self.__ExtractDesignSurfaceData(control_update, self.model_part.Nodes))
169
+
170
+ # now update the shape
171
+ self._UpdateMesh(shape_update)
172
+
173
+ # now output the fields
174
+ un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData()
175
+ un_buffered_data.SetValue("shape_update", shape_update,overwrite=True)
176
+ if self.output_all_fields:
177
+ un_buffered_data.SetValue("shape_control", self.control_field.Clone(), overwrite=True)
178
+ un_buffered_data.SetValue("shape_control_update", control_update.Clone(), overwrite=True)
179
+
180
+ def _UpdateMesh(self, shape_update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
181
+ if self.mesh_motion_solver_type != "none":
182
+ if not self.__mesh_moving_analysis is None:
183
+ mm_computing_model_part: Kratos.ModelPart = self.__mesh_moving_analysis._GetSolver().GetComputingModelPart()
184
+ time_before_update = mm_computing_model_part.ProcessInfo.GetValue(Kratos.TIME)
185
+ step_before_update = mm_computing_model_part.ProcessInfo.GetValue(Kratos.STEP)
186
+ delta_time_before_update = mm_computing_model_part.ProcessInfo.GetValue(Kratos.DELTA_TIME)
187
+
188
+ # Reset step/time iterators such that they match the current iteration after calling RunSolutionLoop (which internally calls CloneTimeStep)
189
+ mm_computing_model_part.ProcessInfo.SetValue(Kratos.STEP, step_before_update-1)
190
+ mm_computing_model_part.ProcessInfo.SetValue(Kratos.TIME, time_before_update-1)
191
+ mm_computing_model_part.ProcessInfo.SetValue(Kratos.DELTA_TIME, 0)
192
+
193
+ # first reset the MESH_DISPLACEMENTS
194
+ Kratos.VariableUtils().SetHistoricalVariableToZero(Kratos.MESH_DISPLACEMENT, mm_computing_model_part.Nodes)
195
+
196
+ # assign the design surface MESH_DISPLACEMENTS
197
+ Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(shape_update, Kratos.MESH_DISPLACEMENT, copy=False).StoreData()
198
+
199
+ # since we know that the nodes in the shape_update model part needs to be fixed to correctly
200
+ # compute the MESH_DISPLACEMENT. We Only do that in here by first freeing all the MESH_DISPLACEMENT
201
+ # dofs, then followed by fixing the shape_update model part nodes' MESH_DISPLACEMENTs. If further
202
+ # boundaries needs fixing, then they need to be specified in the mesh_motion_solver settings
203
+ # using fix_vector_variable_process.
204
+ mesh_displacement_comps = [Kratos.MESH_DISPLACEMENT_X, Kratos.MESH_DISPLACEMENT_Y, Kratos.MESH_DISPLACEMENT_Z]
205
+ for i_comp, mesh_displacement_var in enumerate(mesh_displacement_comps):
206
+ # first free the mesh displacement component
207
+ Kratos.VariableUtils().ApplyFixity(mesh_displacement_var, False, mm_computing_model_part.Nodes)
208
+ # now fix the design surface component
209
+ Kratos.VariableUtils().ApplyFixity(mesh_displacement_var, True, shape_update.GetContainer())
210
+ # now fix boundary condition components
211
+ model_parts = self.filter.GetBoundaryConditions()
212
+ for model_part in model_parts[i_comp]:
213
+ Kratos.VariableUtils().ApplyFixity(mesh_displacement_var, True, model_part.Nodes)
214
+
215
+ # solve for the volume mesh displacements
216
+ if not self.__mesh_moving_analysis.time < self.__mesh_moving_analysis.end_time:
217
+ self.__mesh_moving_analysis.end_time += 1
218
+ self.__mesh_moving_analysis.RunSolutionLoop()
219
+
220
+ mesh_displacement_field = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(self.model_part_operation.GetRootModelPart().Nodes, Kratos.MESH_DISPLACEMENT)
221
+ mesh_displacement_field.CollectData()
222
+
223
+ mm_computing_model_part.ProcessInfo.SetValue(Kratos.STEP, step_before_update)
224
+ mm_computing_model_part.ProcessInfo.SetValue(Kratos.TIME, time_before_update)
225
+ mm_computing_model_part.ProcessInfo.SetValue(Kratos.DELTA_TIME, delta_time_before_update)
226
+ else:
227
+ # filter based mesh motion is used. Hence read the value from the filter. then the shape update is the mesh displacement
228
+ mesh_displacement_field = shape_update
229
+
230
+ # a mesh motion is solved (either by mesh motion solver or the filter), and MESH_DISPLACEMENT variable is filled
231
+ # Hence, update the coords
232
+ physical_field = Kratos.TensorAdaptors.NodePositionTensorAdaptor(mesh_displacement_field.GetContainer(), Kratos.Configuration.Initial)
233
+ physical_field.CollectData()
234
+ physical_field.data += mesh_displacement_field.data
235
+
236
+ Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Initial, copy=False).StoreData()
237
+ Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Current, copy=False).StoreData()
238
+ Kratos.Logger.PrintInfo(self.__class__.__name__, "Applied MESH_DISPLACEMENT to the mesh.")
239
+ else:
240
+ # no mesh motion is preferred, hence only updating the design field
241
+ physical_field = self.GetPhysicalField()
242
+ physical_field.data += shape_update.data
243
+ Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Initial, copy=False).StoreData()
244
+ Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Current, copy=False).StoreData()
245
+
246
+ def __GetPhysicalModelPart(self) -> Kratos.ModelPart:
247
+ if self.mesh_motion_solver_type == "none":
248
+ # this control does not require mesh_motion, hence this does not
249
+ # have any influence on the volume domain. So the physical model part
250
+ # is the controlled model part
251
+ return self.model_part
252
+ else:
253
+ # this is the case where mesh motion is required, that means this control will control the
254
+ # whole domain by moving its internal nodes because, the controlled model part represents
255
+ # a surface of the volume domain. hence the physical field should be the whole
256
+ # model part
257
+ return self.model_part.GetRootModelPart()
258
+
259
+ def __ExtractDesignSurfaceData(self, tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor, nodes_container: Kratos.NodesArray) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
260
+ """\
261
+ @brief This method is used to extract data from model part to @ref TensorAdaptor.
262
+
263
+ @details If the nodes container used in the @p tensor_adaptor is different from the @p nodes_container
264
+ then, this method extracts values from the nodes of the container into the @p tensor_adaptor
265
+ to a @ref TensorAdaptor having @p nodes_container as the nodes.
266
+
267
+ Eg:
268
+ This is required, if mesh motion based filters are used in the filtering, then
269
+ smoothened update from filtering will be computed on the whole domain including the design surface.
270
+ But, for computation of the shape_update and checking it if it actually changes the design surface, first
271
+ we need to get only the design surface update. Hence, this method is used.
272
+
273
+ @param tensor_adaptor (Kratos.TensorAdaptors.DoubleTensorAdaptor): @ref TensorAdaptor with the data.
274
+ @param nodes_container (Kratos.NodesArray): list of nodes on which you needs data transferred.
275
+ @returns: @ref TensorAdaptor having the @p nodes_container as the container, having values extracted from corresponding nodes in the container of @p tensor_adaptor .
276
+ """
277
+ if nodes_container != tensor_adaptor.GetContainer():
278
+ Kratos.VariableUtils().SetNonHistoricalVariableToZero(KratosOA.SHAPE, tensor_adaptor.GetContainer())
279
+ Kratos.VariableUtils().SetNonHistoricalVariableToZero(KratosOA.SHAPE, nodes_container)
280
+
281
+ Kratos.TensorAdaptors.VariableTensorAdaptor(tensor_adaptor, KratosOA.SHAPE, copy=False).StoreData()
282
+ ta = Kratos.TensorAdaptors.VariableTensorAdaptor(nodes_container, KratosOA.SHAPE)
283
+ ta.CollectData()
284
+ return ta
285
+ else:
286
+ return tensor_adaptor
287
+
288
+ def __str__(self) -> str:
289
+ return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = SHAPE ]"