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,149 @@
|
|
|
1
|
+
import numpy
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import KratosMultiphysics as Kratos
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.controls.control import Control
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.filtering.filter import Filter
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
9
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
10
|
+
from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
|
|
11
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
|
|
12
|
+
|
|
13
|
+
def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control:
|
|
14
|
+
if not parameters.Has("name"):
|
|
15
|
+
raise RuntimeError(f"ExternalResponseFunctionControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
|
|
16
|
+
if not parameters.Has("settings"):
|
|
17
|
+
raise RuntimeError(f"ExternalResponseFunctionControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
18
|
+
|
|
19
|
+
return ExternalResponseFunctionControl(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
|
|
20
|
+
|
|
21
|
+
class ExternalResponseFunctionControl(Control):
|
|
22
|
+
def __init__(self, control_name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> None:
|
|
23
|
+
super().__init__(control_name)
|
|
24
|
+
|
|
25
|
+
default_parameters = Kratos.Parameters("""{
|
|
26
|
+
"controlled_model_part_names": [],
|
|
27
|
+
"design_variable" : "CUSTOM_DESIGN_VARIABLE",
|
|
28
|
+
"use_filtering" : false,
|
|
29
|
+
"filter_settings" : {},
|
|
30
|
+
"output_all_fields" : false
|
|
31
|
+
}""")
|
|
32
|
+
parameters.ValidateAndAssignDefaults(default_parameters)
|
|
33
|
+
|
|
34
|
+
self.model = model
|
|
35
|
+
self.optimization_problem = optimization_problem
|
|
36
|
+
|
|
37
|
+
self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", parameters["controlled_model_part_names"].GetStringArray(), False)
|
|
38
|
+
self.model_part: 'Optional[Kratos.ModelPart]' = None
|
|
39
|
+
|
|
40
|
+
self.design_variable: SupportedSensitivityFieldVariableTypes = Kratos.KratosGlobals.GetVariable(parameters["design_variable"].GetString())
|
|
41
|
+
self.output_all_fields = parameters["output_all_fields"].GetBool()
|
|
42
|
+
|
|
43
|
+
if parameters["use_filtering"].GetBool():
|
|
44
|
+
self.filter: 'Optional[Filter]' = FilterFactory(self.model, self.model_part_operation.GetModelPartFullName(), self.design_variable, Kratos.Globals.DataLocation.NodeNonHistorical, parameters["filter_settings"])
|
|
45
|
+
else:
|
|
46
|
+
self.filter = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def Initialize(self) -> None:
|
|
50
|
+
self.model_part = self.model_part_operation.GetModelPart()
|
|
51
|
+
|
|
52
|
+
ComponentDataView(self, self.optimization_problem).SetDataBuffer(1)
|
|
53
|
+
|
|
54
|
+
# initialize the filter
|
|
55
|
+
if self.filter:
|
|
56
|
+
self.filter.SetComponentDataView(ComponentDataView(self, self.optimization_problem))
|
|
57
|
+
self.filter.Initialize()
|
|
58
|
+
|
|
59
|
+
self.physical_phi_field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, self.design_variable)
|
|
60
|
+
self.physical_phi_field.CollectData()
|
|
61
|
+
|
|
62
|
+
if self.filter:
|
|
63
|
+
# take the physical and control field the same
|
|
64
|
+
self.control_phi_field = self.filter.UnfilterField(self.physical_phi_field)
|
|
65
|
+
else:
|
|
66
|
+
self.control_phi_field = self.physical_phi_field.Clone()
|
|
67
|
+
|
|
68
|
+
# now update the physical thickness field
|
|
69
|
+
self._UpdateAndOutputFields(self.GetEmptyField())
|
|
70
|
+
|
|
71
|
+
def Check(self) -> None:
|
|
72
|
+
if self.filter:
|
|
73
|
+
self.filter.Check()
|
|
74
|
+
|
|
75
|
+
def Finalize(self) -> None:
|
|
76
|
+
if self.filter:
|
|
77
|
+
self.filter.Finalize()
|
|
78
|
+
|
|
79
|
+
def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
|
|
80
|
+
return [self.design_variable]
|
|
81
|
+
|
|
82
|
+
def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
|
|
83
|
+
ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, self.design_variable)
|
|
84
|
+
ta.data[:] = 0.0
|
|
85
|
+
return ta
|
|
86
|
+
|
|
87
|
+
def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
|
|
88
|
+
return self.control_phi_field.Clone()
|
|
89
|
+
|
|
90
|
+
def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
|
|
91
|
+
with TimeLogger("ExternalResponseFunctionControl::MapGradient", None, "Finished",False):
|
|
92
|
+
keys = physical_variable_gradient_map.keys()
|
|
93
|
+
if len(keys) != 1:
|
|
94
|
+
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]))
|
|
95
|
+
if self.design_variable not in keys:
|
|
96
|
+
raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.design_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
|
|
97
|
+
|
|
98
|
+
physical_gradient = physical_variable_gradient_map[self.design_variable]
|
|
99
|
+
if physical_gradient.GetContainer() != self.model_part.Nodes:
|
|
100
|
+
raise RuntimeError(f"Gradients for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]")
|
|
101
|
+
|
|
102
|
+
if self.filter:
|
|
103
|
+
# now filter the field
|
|
104
|
+
filtered_gradient = self.filter.BackwardFilterIntegratedField(physical_gradient)
|
|
105
|
+
else:
|
|
106
|
+
filtered_gradient = physical_gradient.Clone()
|
|
107
|
+
|
|
108
|
+
return filtered_gradient
|
|
109
|
+
|
|
110
|
+
def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
|
|
111
|
+
if new_control_field.GetContainer() != self.model_part.Nodes:
|
|
112
|
+
raise RuntimeError(f"Updates for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
|
|
113
|
+
|
|
114
|
+
update = new_control_field.Clone()
|
|
115
|
+
update.data[:] -= self.control_phi_field.data
|
|
116
|
+
if numpy.linalg.norm(update.data) > 1e-15:
|
|
117
|
+
with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False):
|
|
118
|
+
# update the control thickness field
|
|
119
|
+
self.control_phi_field.data[:] = new_control_field.data
|
|
120
|
+
# now update the physical field
|
|
121
|
+
self._UpdateAndOutputFields(update)
|
|
122
|
+
|
|
123
|
+
if self.filter:
|
|
124
|
+
self.filter.Update()
|
|
125
|
+
return True
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
|
|
129
|
+
if self.filter:
|
|
130
|
+
# filter the control field
|
|
131
|
+
filtered_update = self.filter.ForwardFilterField(update)
|
|
132
|
+
else:
|
|
133
|
+
filtered_update = update.Clone()
|
|
134
|
+
|
|
135
|
+
self.physical_phi_field.data[:] += filtered_update.data
|
|
136
|
+
Kratos.TensorAdaptors.VariableTensorAdaptor(self.physical_phi_field, self.design_variable, copy=False).StoreData()
|
|
137
|
+
|
|
138
|
+
# add the values of the control to the optimization problem.
|
|
139
|
+
component_data_view = ComponentDataView(self, self.optimization_problem)
|
|
140
|
+
for i, v in enumerate(self.physical_phi_field.data):
|
|
141
|
+
component_data_view.GetBufferedData().SetValue(f"{self.model_part.FullName()}_point_{i+1}", float(v))
|
|
142
|
+
|
|
143
|
+
# now output the fields
|
|
144
|
+
un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData()
|
|
145
|
+
un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}", self.physical_phi_field.Clone(), overwrite=True)
|
|
146
|
+
if self.output_all_fields:
|
|
147
|
+
un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}_update", update.Clone(), overwrite=True)
|
|
148
|
+
un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}_filtered_update", filtered_update.Clone(), overwrite=True)
|
|
149
|
+
un_buffered_data.SetValue(f"{self.GetName()}_{self.design_variable.Name()}_control_phi", self.control_phi_field.Clone(), overwrite=True)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.controls.control import Control
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll
|
|
7
|
+
|
|
8
|
+
class MasterControl:
|
|
9
|
+
"""Master control class.
|
|
10
|
+
|
|
11
|
+
This class is used to simplify working with many controls at once. Following responsibilities are assumed:
|
|
12
|
+
1. Maps physical gradients from different domains to one @ref Kratos::CombinedTensorAdaptor (using MapGradient).
|
|
13
|
+
2. Updates each respective domain from updates given by one @ref Kratos::CombinedTensorAdaptor (using Update).
|
|
14
|
+
|
|
15
|
+
There should be only one master control class per optimization problem.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self) -> None:
|
|
19
|
+
self.__list_of_controls: 'list[Control]' = []
|
|
20
|
+
|
|
21
|
+
def AddControl(self, control: Control) -> None:
|
|
22
|
+
"""Adds a given control to the master control.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
control (Control): Control to be added
|
|
26
|
+
"""
|
|
27
|
+
self.__list_of_controls.append(control)
|
|
28
|
+
|
|
29
|
+
def GetListOfControls(self) -> 'list[Control]':
|
|
30
|
+
"""Returns the list of controls in the master control.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
list[Control]: List of controls.
|
|
34
|
+
"""
|
|
35
|
+
return self.__list_of_controls
|
|
36
|
+
|
|
37
|
+
def GetPhysicalKratosVariableMap(self) -> 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]':
|
|
38
|
+
"""Returns map of physical variables and @ref Kratos::CombinedTensorAdaptor from each control.
|
|
39
|
+
|
|
40
|
+
This returns a map of physical control variables and a @ref Kratos::CombinedTensorAdaptor. The @ref Kratos::CombinedTensorAdaptor will contain
|
|
41
|
+
all the @ref Kratos::TensorAdaptor for respective control's control domains for each physical control variable. The repeated @ref Kratos::TensorAdaptor s
|
|
42
|
+
for the same physical control variable is omitted to avoid double calculations.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]: Physical control variable and @ref Kratos::CombinedTensorAdaptor map.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
physical_variable_containers_dict: 'dict[SupportedSensitivityFieldVariableTypes, list[typing.Union[Kratos.NodesArray, Kratos.ElementsArray, Kratos.ConditionsArray]]]' = {}
|
|
49
|
+
for control in self.__list_of_controls:
|
|
50
|
+
for physical_variable in control.GetPhysicalKratosVariables():
|
|
51
|
+
# check whether the physical variable is already there.
|
|
52
|
+
if not physical_variable in physical_variable_containers_dict.keys():
|
|
53
|
+
physical_variable_containers_dict[physical_variable] = []
|
|
54
|
+
|
|
55
|
+
# check whether the container for that physical variable is already there.
|
|
56
|
+
control_ta = control.GetEmptyField()
|
|
57
|
+
if control_ta.GetContainer() not in physical_variable_containers_dict[physical_variable]:
|
|
58
|
+
physical_variable_containers_dict[physical_variable].append(control_ta.GetContainer())
|
|
59
|
+
|
|
60
|
+
physical_variable_combined_ta_dict: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {}
|
|
61
|
+
for variable, containers_list in physical_variable_containers_dict.items():
|
|
62
|
+
physical_variable_combined_ta_dict[variable] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.DoubleTensorAdaptor(Kratos.TensorAdaptors.VariableTensorAdaptor(container, variable), copy=False) for container in containers_list], perform_collect_data_recursively=False, perform_store_data_recursively=False)
|
|
63
|
+
|
|
64
|
+
return physical_variable_combined_ta_dict
|
|
65
|
+
|
|
66
|
+
def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
67
|
+
"""Returns empty CombinedTensorAdaptor containing empty TensorAdaptor for each control.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Empty CombinedTensorAdaptor
|
|
71
|
+
"""
|
|
72
|
+
ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetEmptyField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False)
|
|
73
|
+
ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor
|
|
74
|
+
return ta
|
|
75
|
+
|
|
76
|
+
def GetControlField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
77
|
+
"""Returns CombinedTensorAdaptor containing control field TensorAdaptor for each control.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control field CombinedTensorAdaptor
|
|
81
|
+
"""
|
|
82
|
+
ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetControlField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False)
|
|
83
|
+
ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor
|
|
84
|
+
return ta
|
|
85
|
+
|
|
86
|
+
@time_decorator()
|
|
87
|
+
def MapGradient(self, physical_space_gradient_variable_and_combined_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
|
|
88
|
+
"""Maps physical space gradients to a combined tensor adaptor.
|
|
89
|
+
|
|
90
|
+
This method maps sensitivities w.r.t. physical space variables to control space by using each control. It is done by converting input
|
|
91
|
+
map with @ref Kratos::CombinedTensorAdaptor to a map with @ref Kratos::TensorAdaptor. The following is a pseudo example:
|
|
92
|
+
|
|
93
|
+
input:
|
|
94
|
+
|
|
95
|
+
physical_space_gradient_variable_and_combined_tensor_adaptor_map = {
|
|
96
|
+
"YOUND_MODULUS": [ControlDomain1, ControlDomain2],
|
|
97
|
+
"DENSITY" : [ControlDomain1],
|
|
98
|
+
"VISCOSITY" : [ControlDomain2],
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
control info:
|
|
102
|
+
control1: domain = ControlDomain1
|
|
103
|
+
physical_vars = YOUND_MODULUS, DENSITY
|
|
104
|
+
|
|
105
|
+
control2: domain = ControlDomain2
|
|
106
|
+
physical_vars = VISCOSITY, DENSITY
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
from above information, following two maps are created and passed to each control to obtain one @ref Kratos::TensorAdaptor from each control.
|
|
110
|
+
control_specific_maps:
|
|
111
|
+
for control1: {YOUND_MODULUS: ControlDomain1, DENSITY: ControlDomain1}
|
|
112
|
+
for control2: {VISCOSITY: ControlDomain2, DENSITY: A zero valued ControlDomain}
|
|
113
|
+
|
|
114
|
+
then returned mapped gradients are added to one @ref Kratos::CombinedTensorAdaptor.
|
|
115
|
+
|
|
116
|
+
In here, the missing gradients for required physical variables will be assumed to be zero.
|
|
117
|
+
|
|
118
|
+
This converts given map of sensitivities w.r.t. different physical space variables to one sensitivities in control space and aggregated
|
|
119
|
+
to one @ref Kratos::CombinedTensorAdaptor.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
physical_space_gradient_variable_and_combined_tensor_adaptor_map (dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]): Map of physical space sensitivities.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control space sensitivities.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
mapped_gradients: 'list[Kratos.TensorAdaptors.DoubleTensorAdaptor]' = []
|
|
130
|
+
|
|
131
|
+
for control in self.__list_of_controls:
|
|
132
|
+
# iterate through each control to create its own container map from the combined tensor adaptor map given as input
|
|
133
|
+
control_physical_sensitivities_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]' = {}
|
|
134
|
+
for physical_control_variable in control.GetPhysicalKratosVariables():
|
|
135
|
+
# first assume the gradients for this physical_control_variable is zero, hence get the zero valued tensor adaptor.
|
|
136
|
+
control_ta = control.GetEmptyField()
|
|
137
|
+
|
|
138
|
+
# get the required physical variables from control.
|
|
139
|
+
if physical_control_variable in physical_space_gradient_variable_and_combined_tensor_adaptor_map.keys():
|
|
140
|
+
# if the sensitivities for the given physical control variable exists, then try to find whether
|
|
141
|
+
# for this specific control the physical control variable sensitivities exists.
|
|
142
|
+
|
|
143
|
+
sensitivity_cta = physical_space_gradient_variable_and_combined_tensor_adaptor_map[physical_control_variable]
|
|
144
|
+
for ta in sensitivity_cta.GetTensorAdaptors():
|
|
145
|
+
if ta.GetContainer() == control_ta.GetContainer():
|
|
146
|
+
# there exists for this control's physical variables sensitivities.
|
|
147
|
+
control_physical_sensitivities_tensor_adaptor_map[physical_control_variable] = ta
|
|
148
|
+
break
|
|
149
|
+
|
|
150
|
+
if physical_control_variable not in control_physical_sensitivities_tensor_adaptor_map.keys():
|
|
151
|
+
# If it is found from input gradients, the tensor_adaptor will have those values,
|
|
152
|
+
# otherwise it will have representative zero tensor_adaptor.
|
|
153
|
+
control_physical_sensitivities_tensor_adaptor_map[physical_control_variable] = control_ta
|
|
154
|
+
|
|
155
|
+
# map the physical control variable sensitivities to one control space
|
|
156
|
+
mapped_gradients.append(control.MapGradient(control_physical_sensitivities_tensor_adaptor_map))
|
|
157
|
+
|
|
158
|
+
result = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([mapped_gradient for mapped_gradient in mapped_gradients], perform_collect_data_recursively=False, perform_store_data_recursively=False)
|
|
159
|
+
result.CollectData()
|
|
160
|
+
return result
|
|
161
|
+
|
|
162
|
+
@time_decorator()
|
|
163
|
+
def Update(self, update_combined_tensor_adaptor: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> 'dict[Control, bool]':
|
|
164
|
+
"""Update each control with given combined tensor adaptor's respective tensor adaptor.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
update_combined_tensor_adaptor (Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): Update
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
RuntimeError: If number of controls and number of tensor adaptors mismatch.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
dict[Control, bool]: A map with control and a boolean whether the update changed anything in that control.
|
|
174
|
+
"""
|
|
175
|
+
if len(self.__list_of_controls) != len(update_combined_tensor_adaptor.GetTensorAdaptors()):
|
|
176
|
+
raise RuntimeError(f"Controls size and update size mismatch [ number of controls: {len(self.__list_of_controls)}, number of tensor adaptors: {len(update_combined_tensor_adaptor.GetTensorAdaptors())} ].")
|
|
177
|
+
|
|
178
|
+
update_map: 'dict[Control, bool]' = {}
|
|
179
|
+
for control, ta in zip(self.__list_of_controls, update_combined_tensor_adaptor.GetTensorAdaptors()):
|
|
180
|
+
update_map[control] = control.Update(ta)
|
|
181
|
+
if update_map[control]:
|
|
182
|
+
Kratos.Logger.PrintInfo(f"Control {control.GetName()} updated.")
|
|
183
|
+
else:
|
|
184
|
+
Kratos.Logger.PrintInfo(f"Control {control.GetName()} not updated")
|
|
185
|
+
|
|
186
|
+
return update_map
|
|
187
|
+
|
|
188
|
+
def Check(self) -> None:
|
|
189
|
+
CallOnAll(self.__list_of_controls, Control.Check)
|
|
190
|
+
|
|
191
|
+
def Initialize(self) -> None:
|
|
192
|
+
CallOnAll(self.__list_of_controls, Control.Initialize)
|
|
193
|
+
|
|
194
|
+
def Finalize(self) -> None:
|
|
195
|
+
CallOnAll(self.__list_of_controls, Control.Finalize)
|
|
196
|
+
|
|
197
|
+
def GetName(self) -> str:
|
|
198
|
+
return "master_control"
|
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
|
|
10
|
+
def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> Control:
|
|
11
|
+
if not parameters.Has("name"):
|
|
12
|
+
raise RuntimeError(f"MaterialPropertiesControl instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
|
|
13
|
+
if not parameters.Has("settings"):
|
|
14
|
+
raise RuntimeError(f"MaterialPropertiesControl instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
15
|
+
|
|
16
|
+
return MaterialPropertiesControl(parameters["name"].GetString(), model, parameters["settings"])
|
|
17
|
+
|
|
18
|
+
class MaterialPropertiesControl(Control):
|
|
19
|
+
"""Material properties control
|
|
20
|
+
|
|
21
|
+
This is a generic material properties control which creates a control
|
|
22
|
+
for the specified control variable. This does not do any filtering.
|
|
23
|
+
|
|
24
|
+
TODO: Extend with filtering techniques when they are implemented.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters):
|
|
28
|
+
super().__init__(name)
|
|
29
|
+
|
|
30
|
+
default_settings = Kratos.Parameters("""{
|
|
31
|
+
"model_part_names" : [""],
|
|
32
|
+
"control_variable_name" : "",
|
|
33
|
+
"consider_recursive_property_update": false
|
|
34
|
+
}""")
|
|
35
|
+
parameters.ValidateAndAssignDefaults(default_settings)
|
|
36
|
+
|
|
37
|
+
self.model = model
|
|
38
|
+
|
|
39
|
+
control_variable_name = parameters["control_variable_name"].GetString()
|
|
40
|
+
control_variable_type = Kratos.KratosGlobals.GetVariableType(control_variable_name)
|
|
41
|
+
if control_variable_type != "Double":
|
|
42
|
+
raise RuntimeError(f"{control_variable_name} with {control_variable_type} type is not supported. Only supports double variables")
|
|
43
|
+
self.controlled_physical_variable = Kratos.KratosGlobals.GetVariable(control_variable_name)
|
|
44
|
+
|
|
45
|
+
controlled_model_part_names = parameters["model_part_names"].GetStringArray()
|
|
46
|
+
if len(controlled_model_part_names) == 0:
|
|
47
|
+
raise RuntimeError(f"No model parts were provided for MaterialPropertiesControl. [ control name = \"{self.GetName()}\"]")
|
|
48
|
+
|
|
49
|
+
self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"control_{self.GetName()}", controlled_model_part_names, False)
|
|
50
|
+
self.model_part: Optional[Kratos.ModelPart] = None
|
|
51
|
+
|
|
52
|
+
self.consider_recursive_property_update = parameters["consider_recursive_property_update"].GetBool()
|
|
53
|
+
|
|
54
|
+
def Initialize(self) -> None:
|
|
55
|
+
self.model_part = self.model_part_operation.GetModelPart()
|
|
56
|
+
|
|
57
|
+
if not KratosOA.OptAppModelPartUtils.CheckModelPartStatus(self.model_part, "element_specific_properties_created"):
|
|
58
|
+
KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(self.model_part, self.model_part.Elements, self.consider_recursive_property_update)
|
|
59
|
+
KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.model_part, "element_specific_properties_created")
|
|
60
|
+
|
|
61
|
+
def Check(self) -> None:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def Finalize(self) -> None:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
|
|
68
|
+
return [self.controlled_physical_variable]
|
|
69
|
+
|
|
70
|
+
def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
|
|
71
|
+
field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, self.controlled_physical_variable)
|
|
72
|
+
field.data[:] = 0.0
|
|
73
|
+
return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False)
|
|
74
|
+
|
|
75
|
+
def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
|
|
76
|
+
field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, self.controlled_physical_variable)
|
|
77
|
+
field.CollectData()
|
|
78
|
+
return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False)
|
|
79
|
+
|
|
80
|
+
def MapGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor:
|
|
81
|
+
keys = physical_variable_gradient_map.keys()
|
|
82
|
+
if len(keys) != 1:
|
|
83
|
+
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]))
|
|
84
|
+
if self.controlled_physical_variable not in keys:
|
|
85
|
+
raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.controlled_physical_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys]))
|
|
86
|
+
|
|
87
|
+
physical_gradient = physical_variable_gradient_map[self.controlled_physical_variable]
|
|
88
|
+
if physical_gradient.GetContainer() != self.GetEmptyField().GetContainer():
|
|
89
|
+
raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
|
|
90
|
+
|
|
91
|
+
# TODO: Implement filtering mechanisms here
|
|
92
|
+
return physical_variable_gradient_map[self.controlled_physical_variable].Clone()
|
|
93
|
+
|
|
94
|
+
def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool:
|
|
95
|
+
if control_field.GetContainer() != self.GetEmptyField().GetContainer():
|
|
96
|
+
raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]")
|
|
97
|
+
|
|
98
|
+
# TODO: Implement inverse filtering mechanisms here
|
|
99
|
+
# since no filtering is implemented yet, we are checking the unfiltered updates with the filtered updates. This needs to be changed once the
|
|
100
|
+
# filtering mechanisms are implemented.
|
|
101
|
+
|
|
102
|
+
# get the current unfiltered control field
|
|
103
|
+
unfiltered_control_field = self.GetControlField()
|
|
104
|
+
|
|
105
|
+
if numpy.linalg.norm(unfiltered_control_field.data - control_field.data) > 1e-9:
|
|
106
|
+
KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(control_field, self.controlled_physical_variable, copy=False).StoreData()
|
|
107
|
+
|
|
108
|
+
if self.consider_recursive_property_update:
|
|
109
|
+
KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(control_field.GetContainer(), self.controlled_physical_variable)
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
def __str__(self) -> str:
|
|
115
|
+
return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = {self.controlled_physical_variable.Name()}"
|