KratosSystemIdentificationApplication 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 (27) hide show
  1. KratosMultiphysics/.libs/KratosSystemIdentificationApplication.so +0 -0
  2. KratosMultiphysics/.libs/libKratosSystemIdentificationCore.dylib +0 -0
  3. KratosMultiphysics/SystemIdentificationApplication/__init__.py +13 -0
  4. KratosMultiphysics/SystemIdentificationApplication/controls/data_values_control.py +210 -0
  5. KratosMultiphysics/SystemIdentificationApplication/controls/material_properties_control.py +212 -0
  6. KratosMultiphysics/SystemIdentificationApplication/convergence_criteria/sensor_error.py +93 -0
  7. KratosMultiphysics/SystemIdentificationApplication/processes/sensor_output_process.py +83 -0
  8. KratosMultiphysics/SystemIdentificationApplication/python_registry_lists.py +9 -0
  9. KratosMultiphysics/SystemIdentificationApplication/responses/damage_detection_response.py +190 -0
  10. KratosMultiphysics/SystemIdentificationApplication/responses/pressure_detection_response.py +20 -0
  11. KratosMultiphysics/SystemIdentificationApplication/responses/temperature_detection_response.py +20 -0
  12. KratosMultiphysics/SystemIdentificationApplication/sensor_generator_analysis.py +130 -0
  13. KratosMultiphysics/SystemIdentificationApplication/sensor_io/sensor_model_part_controller.py +58 -0
  14. KratosMultiphysics/SystemIdentificationApplication/sensor_sensitivity_solvers/response_sensitivity_analysis.py +41 -0
  15. KratosMultiphysics/SystemIdentificationApplication/sensor_sensitivity_solvers/response_sensitivity_interface.py +34 -0
  16. KratosMultiphysics/SystemIdentificationApplication/sensor_sensitivity_solvers/sensor_sensitivity_adjoint_static_solver.py +50 -0
  17. KratosMultiphysics/SystemIdentificationApplication/sensor_sensitivity_solvers/system_identification_static_analysis.py +52 -0
  18. KratosMultiphysics/SystemIdentificationApplication/utilities/data_utils.py +67 -0
  19. KratosMultiphysics/SystemIdentificationApplication/utilities/sensor_utils.py +196 -0
  20. KratosMultiphysics/SystemIdentificationApplication/utilities/tensor_adaptor_utils.py +63 -0
  21. kratossystemidentificationapplication-10.4.4.dist-info/METADATA +11 -0
  22. kratossystemidentificationapplication-10.4.4.dist-info/RECORD +27 -0
  23. kratossystemidentificationapplication-10.4.4.dist-info/WHEEL +6 -0
  24. kratossystemidentificationapplication.dylibs/libKratosCore.dylib +4 -0
  25. kratossystemidentificationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
  26. kratossystemidentificationapplication.dylibs/libgomp.1.dylib +0 -0
  27. kratossystemidentificationapplication.dylibs/libstdc++.6.dylib +0 -0
@@ -0,0 +1,190 @@
1
+ from typing import Optional
2
+ import csv
3
+
4
+ import KratosMultiphysics as Kratos
5
+ import KratosMultiphysics.SystemIdentificationApplication as KratosSI
6
+ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction
7
+ from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes
8
+ from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
9
+ from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy_decorator import ExecutionPolicyDecorator
10
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
11
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
12
+ from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.system_identification_static_analysis import SystemIdentificationStaticAnalysis
13
+ from KratosMultiphysics.SystemIdentificationApplication.utilities.sensor_utils import GetSensors
14
+ from KratosMultiphysics.SystemIdentificationApplication.utilities.sensor_utils import SetSensorNormalizationFactor
15
+
16
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ResponseFunction:
17
+ if not parameters.Has("name"):
18
+ raise RuntimeError(f"DamageDetectionResponse instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
19
+ if not parameters.Has("settings"):
20
+ raise RuntimeError(f"DamageDetectionResponse instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
21
+ return DamageDetectionResponse(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
22
+
23
+
24
+ class DamageDetectionResponse(ResponseFunction):
25
+ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
26
+ super().__init__(name)
27
+
28
+ default_settings = Kratos.Parameters("""{
29
+ "sensor_group_name" : "",
30
+ "p_coefficient" : 1,
31
+ "adjoint_parameters" : {},
32
+ "evaluated_model_part_names" : [
33
+ "PLEASE_PROVIDE_A_MODEL_PART_NAME"
34
+ ],
35
+ "test_analysis_list": [
36
+ {
37
+ "primal_analysis_name": "Structure_static",
38
+ "sensor_measurement_csv_file": "measurement_data.csv",
39
+ "weight": 1.0,
40
+ "sensor_normalization_settings": {
41
+ "type": "none"
42
+ },
43
+ "variable_io_settings": {
44
+ "model_part_name" : "Structure",
45
+ "nodal_hist_variable_names" : [],
46
+ "nodal_non_hist_variable_names": [],
47
+ "condition_variable_names" : [],
48
+ "element_variable_names" : [],
49
+ "condition_property_names" : [],
50
+ "element_property_names" : []
51
+ }
52
+ }
53
+ ]
54
+ }""")
55
+ parameters.ValidateAndAssignDefaults(default_settings)
56
+
57
+ self.model = model
58
+ self.sensor_group_name = parameters["sensor_group_name"].GetString()
59
+
60
+ if self.sensor_group_name == "":
61
+ raise RuntimeError(f"The sensor group name cannot be empty.")
62
+
63
+ self.p_coefficient = parameters["p_coefficient"].GetDouble()
64
+
65
+ evaluated_model_part_names = parameters["evaluated_model_part_names"].GetStringArray()
66
+ if len(evaluated_model_part_names) == 0:
67
+ raise RuntimeError(f"No model parts were provided for {self._GetResponsePrefix()}. [ response name = \"{self.GetName()}\"]")
68
+
69
+ # reading test analsis list
70
+ self.list_of_test_analysis_data: 'list[tuple[ExecutionPolicyDecorator, str, Kratos.Parameters, float]]' = []
71
+ for params in parameters["test_analysis_list"].values():
72
+ params.ValidateAndAssignDefaults(default_settings["test_analysis_list"][0])
73
+ primal_analysis_name = params["primal_analysis_name"].GetString()
74
+ sensor_measurement_data_file_name = params["sensor_measurement_csv_file"].GetString()
75
+ sensor_normalization_settings = params["sensor_normalization_settings"]
76
+ weight = params["weight"].GetDouble()
77
+ self.list_of_test_analysis_data.append((optimization_problem.GetExecutionPolicy(primal_analysis_name), sensor_measurement_data_file_name, sensor_normalization_settings, weight))
78
+
79
+ self.model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"response_{self.GetName()}", evaluated_model_part_names, False)
80
+ self.model_part: Optional[Kratos.ModelPart] = None
81
+
82
+ self.analysis_model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"response_test_analysis_{self.GetName()}", [exec.GetAnalysisModelPart().FullName() for exec, _, _, _ in self.list_of_test_analysis_data], False)
83
+ self.analysis_model_part: Optional[Kratos.ModelPart] = None
84
+
85
+ self.adjoint_analysis = SystemIdentificationStaticAnalysis(self.model, parameters["adjoint_parameters"])
86
+
87
+ self.sensor_name_dict: 'dict[str, KratosSI.Sensors.Sensor]' = {}
88
+ self.optimization_problem = optimization_problem
89
+
90
+ def GetImplementedPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
91
+ return [Kratos.YOUNG_MODULUS]
92
+
93
+ def Initialize(self) -> None:
94
+ self.model_part = self.model_part_operation.GetModelPart()
95
+ self.analysis_model_part = self.analysis_model_part_operation.GetModelPart()
96
+
97
+ self.adjoint_analysis.Initialize()
98
+
99
+ self.damage_response_function = KratosSI.Responses.MeasurementResidualResponseFunction(self.p_coefficient)
100
+
101
+ if not self.optimization_problem.GetProblemDataContainer()["object"].HasValue(self.sensor_group_name):
102
+ raise RuntimeError(f"The sensor group \"{self.sensor_group_name}\" not found. Followings are available: \n\t" + "\n\t".join(self.optimization_problem.GetProblemDataContainer()["object"].GetSubItems().keys()))
103
+
104
+ sensor_group_data = ComponentDataView(self.sensor_group_name, self.optimization_problem)
105
+ self.list_of_sensors = GetSensors(sensor_group_data)
106
+ for sensor in self.list_of_sensors:
107
+ sensor.GetNode().SetValue(KratosSI.SENSOR_MEASURED_VALUE, 0.0)
108
+ sensor.GetNode().SetValue(KratosSI.SENSOR_NORMALIZATION_FACTOR, 1.0)
109
+ self.damage_response_function.AddSensor(sensor)
110
+
111
+ self.damage_response_function.Initialize()
112
+
113
+ for sensor in self.list_of_sensors:
114
+ self.sensor_name_dict[sensor.GetName()] = sensor
115
+
116
+ def Check(self) -> None:
117
+ pass
118
+
119
+ def Finalize(self) -> None:
120
+ self.adjoint_analysis.Finalize()
121
+
122
+ def GetInfluencingModelPart(self) -> Kratos.ModelPart:
123
+ if self.analysis_model_part is None:
124
+ raise RuntimeError(f"Please call {self._GetResponsePrefix()}::Initialize first.")
125
+ return self.analysis_model_part
126
+
127
+ def CalculateValue(self) -> float:
128
+ result = 0.0
129
+ for exec_policy, sensor_measurement_data_file_name, sensor_normalization_settings, test_case_weight in self.list_of_test_analysis_data:
130
+ # first run the primal analysis.
131
+ exec_policy.Execute()
132
+
133
+ self.__SetSensorMeasuredValue(sensor_measurement_data_file_name)
134
+ SetSensorNormalizationFactor(self.list_of_sensors, sensor_normalization_settings)
135
+
136
+ result += test_case_weight * self.damage_response_function.CalculateValue(exec_policy.GetAnalysisModelPart())
137
+ Kratos.Logger.PrintInfo(self._GetResponsePrefix(), f"Computed \"{exec_policy.GetName()}\".")
138
+
139
+ return result
140
+
141
+ def CalculateGradient(self, physical_variable_gradient_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None:
142
+ # make everything zeros
143
+ for physical_variable, cta in physical_variable_gradient_map.items():
144
+ cta.data[:] = 0.0
145
+ Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_store_data_recursively=False, copy=False).StoreData()
146
+
147
+ # now compute sensitivities for each test scenario
148
+ for exec_policy, sensor_measurement_data_file_name, sensor_normalization_settings, test_case_weight in self.list_of_test_analysis_data:
149
+ # read and replace the measurement data for each test scenario
150
+ self.__SetSensorMeasuredValue(sensor_measurement_data_file_name)
151
+ SetSensorNormalizationFactor(self.list_of_sensors, sensor_normalization_settings)
152
+
153
+ # run a single adjoint for each test scenario
154
+ self.adjoint_analysis._GetSolver().GetComputingModelPart().ProcessInfo[KratosSI.TEST_ANALYSIS_NAME] = exec_policy.GetName()
155
+ self.adjoint_analysis._GetSolver().GetComputingModelPart().ProcessInfo[Kratos.STEP] = self.optimization_problem.GetStep()
156
+ self.adjoint_analysis.CalculateGradient(self.damage_response_function)
157
+
158
+ for physical_variable, cta in physical_variable_gradient_map.items():
159
+ sensitivity_variable = Kratos.KratosGlobals.GetVariable(Kratos.SensitivityUtilities.GetSensitivityVariableName(physical_variable))
160
+ for ta in cta.GetTensorAdaptors():
161
+ current_gradient = ta.Clone()
162
+ self.adjoint_analysis.GetGradient(sensitivity_variable, current_gradient)
163
+ ta.data[:] -= current_gradient.data[:] * test_case_weight
164
+ Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_collect_data_recursively=False, copy=False).CollectData()
165
+
166
+ def __GetSensor(self, sensor_name: str) -> KratosSI.Sensors.Sensor:
167
+ return self.sensor_name_dict[sensor_name]
168
+
169
+ def __GetHeaderIndices(self, csv_stream: csv.reader) -> 'tuple[int, int]':
170
+ headers = [s.strip() for s in next(csv_stream)]
171
+ name_index = headers.index("name")
172
+ value_index = headers.index("value")
173
+ return name_index, value_index
174
+
175
+ def __SetSensorMeasuredValue(self, sensor_measurement_data_file_name: str) -> None:
176
+ with open(sensor_measurement_data_file_name, "r") as csv_measurement_file:
177
+ csv_measurement_stream = csv.reader(csv_measurement_file, delimiter=",")
178
+ measured_name_index, measured_value_index = self.__GetHeaderIndices(csv_measurement_stream)
179
+
180
+ for measured_row in csv_measurement_stream:
181
+ measured_sensor_name = measured_row[measured_name_index].strip()
182
+ measured_value = float(measured_row[measured_value_index])
183
+ if measured_sensor_name in self.sensor_name_dict:
184
+ self.__GetSensor(measured_sensor_name).GetNode().SetValue(KratosSI.SENSOR_MEASURED_VALUE, measured_value)
185
+
186
+ def _GetResponsePrefix(self) -> str:
187
+ return "DamageDetectionResponse"
188
+
189
+ def __str__(self) -> str:
190
+ return f"Response [type = {self._GetResponsePrefix()}, name = {self.GetName()}, model part name = {self.model_part.FullName()}]"
@@ -0,0 +1,20 @@
1
+ import KratosMultiphysics as Kratos
2
+ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction
3
+ from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes
4
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
5
+ from KratosMultiphysics.SystemIdentificationApplication.responses.damage_detection_response import DamageDetectionResponse
6
+
7
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ResponseFunction:
8
+ if not parameters.Has("name"):
9
+ raise RuntimeError(f"PressureDetectionResponse instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
10
+ if not parameters.Has("settings"):
11
+ raise RuntimeError(f"PressureDetectionResponse instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
12
+ return PressureDetectionResponse(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
13
+
14
+
15
+ class PressureDetectionResponse(DamageDetectionResponse):
16
+ def GetImplementedPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
17
+ return [Kratos.PRESSURE]
18
+
19
+ def _GetResponsePrefix(self) -> str:
20
+ return "PressureDetectionResponse"
@@ -0,0 +1,20 @@
1
+ import KratosMultiphysics as Kratos
2
+ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction
3
+ from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes
4
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
5
+ from KratosMultiphysics.SystemIdentificationApplication.responses.damage_detection_response import DamageDetectionResponse
6
+
7
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ResponseFunction:
8
+ if not parameters.Has("name"):
9
+ raise RuntimeError(f"TemperatureDetectionResponse instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
10
+ if not parameters.Has("settings"):
11
+ raise RuntimeError(f"TemperatureDetectionResponse instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
12
+ return TemperatureDetectionResponse(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)
13
+
14
+
15
+ class TemperatureDetectionResponse(DamageDetectionResponse):
16
+ def GetImplementedPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
17
+ return [Kratos.TEMPERATURE]
18
+
19
+ def _GetResponsePrefix(self) -> str:
20
+ return "TemperatureDetectionResponse"
@@ -0,0 +1,130 @@
1
+ import typing
2
+ import json
3
+
4
+ import KratosMultiphysics as Kratos
5
+ import KratosMultiphysics.SystemIdentificationApplication as KratosSI
6
+
7
+ class SensorGeneratorAnalysis:
8
+ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters) -> None:
9
+ default_settings = Kratos.Parameters("""{
10
+ "model_part_name" : "PLEASE_SPECIFY_MODEL_PART_NAME",
11
+ "mdpa_file_name" : "PlEASE_SPECIFY_FILE_NAME",
12
+ "output_file_name" : "sensor_data.json",
13
+ "csv_output_file_name": "sensor_data.csv",
14
+ "sensor_groups" : [
15
+ {
16
+ "generation_method": "mesh_based",
17
+ "container_type" : "elements",
18
+ "location" : "center",
19
+ "sensor_settings" : {}
20
+ }
21
+ ]
22
+ }""")
23
+
24
+ self.parameters = parameters
25
+ self.parameters.ValidateAndAssignDefaults(default_settings)
26
+ self.model = model
27
+
28
+ model_part_name = self.parameters["model_part_name"].GetString()
29
+ root_model_part = model_part_name.split(".")[0]
30
+ self.root_model_part = self.model.CreateModelPart(root_model_part)
31
+
32
+ def Run(self) -> None:
33
+ Kratos.ModelPartIO(self.parameters["mdpa_file_name"].GetString(), Kratos.ModelPartIO.READ | Kratos.ModelPartIO.MESH_ONLY).ReadModelPart(self.root_model_part)
34
+ self.model_part = self.model[self.parameters["model_part_name"].GetString()]
35
+
36
+ sensors_dict = {"list_of_sensors": []}
37
+ for sensor_group in self.parameters["sensor_groups"].values():
38
+ generation_method = sensor_group["generation_method"].GetString()
39
+ if generation_method == "mesh_based":
40
+ self.__GenerateMeshBased(sensors_dict, sensor_group)
41
+ elif generation_method == "bounding_surface":
42
+ self.__GenerationBoundingSurfaceBased(sensors_dict, sensor_group)
43
+ else:
44
+ raise RuntimeError("Unsupported generation method")
45
+
46
+ with open(self.parameters["output_file_name"].GetString(), "w") as file_output:
47
+ file_output.write(json.dumps(sensors_dict, indent=4))
48
+
49
+ with open(self.parameters["csv_output_file_name"].GetString(), "w") as file_output:
50
+ file_output.write("#,name,location_0,location_1,location_2\n")
51
+ for i, sensor_info in enumerate(sensors_dict["list_of_sensors"]):
52
+ name = sensor_info["name"]
53
+ location = sensor_info["location"]
54
+ file_output.write(f"{i+1},{name},{location[0]},{location[1]},{location[2]}\n")
55
+
56
+ def __GenerationBoundingSurfaceBased(self, sensors_dict, sensor_group_params: Kratos.Parameters):
57
+ defaults = Kratos.Parameters("""{
58
+ "generation_method" : "bounding_surface",
59
+ "bounding_surface_corner_1": [0.0, 0.0, 0.0],
60
+ "bounding_surface_corner_2": [0.0, 0.0, 0.0],
61
+ "number_of_sensors" : [1, 1, 1],
62
+ "sensor_settings" : {}
63
+ }""")
64
+ sensor_group_params.ValidateAndAssignDefaults(defaults)
65
+
66
+ point_locator = Kratos.BruteForcePointLocator(self.model_part)
67
+
68
+ corner_1 = sensor_group_params["bounding_surface_corner_1"].GetVector()
69
+ corner_2 = sensor_group_params["bounding_surface_corner_2"].GetVector()
70
+ number_of_sensors = sensor_group_params["number_of_sensors"].GetVector()
71
+ number_of_sensors = [int(v) for v in number_of_sensors]
72
+
73
+ sensor_params = sensor_group_params["sensor_settings"]
74
+ if not sensor_params.Has("location"):
75
+ sensor_params.AddVector("location", Kratos.Vector())
76
+
77
+ distance = corner_2 - corner_1
78
+ index = 1
79
+ for i_x in range(number_of_sensors[0]):
80
+ x_coord = corner_1[0] + distance[0] * (i_x + 1) / (number_of_sensors[0] + 1)
81
+ for i_y in range(number_of_sensors[1]):
82
+ y_coord = corner_1[1] + distance[1] * (i_y + 1) / (number_of_sensors[1] + 1)
83
+ for i_z in range(number_of_sensors[2]):
84
+ z_coord = corner_1[2] + distance[2] * (i_z + 1) / (number_of_sensors[2] + 1)
85
+ loc = Kratos.Point(x_coord, y_coord, z_coord)
86
+ shape_funcs = Kratos.Vector()
87
+ elem_id = point_locator.FindElement(loc, shape_funcs, Kratos.Configuration.Initial, 1e-8)
88
+ if elem_id != -1 and KratosSI.SensorUtils.IsPointInGeometry(loc, self.model_part.GetElement(elem_id).GetGeometry()):
89
+ current_params = sensor_params.Clone()
90
+ current_params["location"].SetVector(loc)
91
+ json_dict = json.loads(current_params.WriteJsonString().replace("<ENTITY_ID>", str(index)))
92
+ index += 1
93
+ sensors_dict["list_of_sensors"].append(json_dict)
94
+
95
+ def __GenerateMeshBased(self, sensors_dict, sensor_group_params: Kratos.Parameters):
96
+ defaults = Kratos.Parameters("""{
97
+ "generation_method": "mesh_based",
98
+ "container_type" : "elements",
99
+ "location" : "center",
100
+ "sensor_settings" : {}
101
+ }""")
102
+ sensor_group_params.ValidateAndAssignDefaults(defaults)
103
+ container_type = sensor_group_params["container_type"].GetString()
104
+ container: 'typing.Union[Kratos.ElementsArray, Kratos.ConditionsArray]'
105
+ if container_type == "nodes":
106
+ container = self.model_part.Nodes
107
+ elif container_type == "elements":
108
+ container = self.model_part.Elements
109
+ elif container_type == "conditions":
110
+ container = self.model_part.Conditions
111
+ else:
112
+ raise RuntimeError(f"Unsupported container_type = \"{container_type}\".")
113
+
114
+ sensor_params = sensor_group_params["sensor_settings"]
115
+ if not sensor_params.Has("location"):
116
+ sensor_params.AddVector("location", Kratos.Vector())
117
+
118
+ location = sensor_group_params["location"].GetString()
119
+ if container_type == "nodes":
120
+ location_retrieval = lambda x: [x.X, x.Y, x.Z]
121
+ elif location == "center":
122
+ location_retrieval = lambda x: x.GetGeometry().Center()
123
+ else:
124
+ raise RuntimeError(f"Unsupported location = \"{location}\".")
125
+
126
+ for entity in container:
127
+ current_params = sensor_params.Clone()
128
+ current_params["location"].SetVector(location_retrieval(entity))
129
+ json_dict = json.loads(current_params.WriteJsonString().replace("<ENTITY_ID>", str(entity.Id)))
130
+ sensors_dict["list_of_sensors"].append(json_dict)
@@ -0,0 +1,58 @@
1
+ import KratosMultiphysics as Kratos
2
+ from KratosMultiphysics.OptimizationApplication.model_part_controllers.model_part_controller import ModelPartController
3
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
4
+ from KratosMultiphysics.SystemIdentificationApplication.utilities.sensor_utils import CreateSensors
5
+ from KratosMultiphysics.SystemIdentificationApplication.utilities.sensor_utils import SetSensors
6
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
7
+
8
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ModelPartController:
9
+ if not parameters.Has("settings"):
10
+ raise RuntimeError(f"SensorModelPartController instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
11
+ return SensorModelPartController(model, parameters["settings"], optimization_problem)
12
+
13
+ class SensorModelPartController(ModelPartController):
14
+ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
15
+ default_settings = Kratos.Parameters("""{
16
+ "sensor_group_name" : "",
17
+ "domain_model_part_name" : "",
18
+ "list_of_sensors" : [],
19
+ "debug_output" : false,
20
+ "debug_output_filename" : "domain_model_part.vtu"
21
+ }""")
22
+
23
+ self.model = model
24
+ self.optimization_problem = optimization_problem
25
+ self.parameters = parameters
26
+ self.parameters.ValidateAndAssignDefaults(default_settings)
27
+
28
+ self.domain_model_part_name = parameters["domain_model_part_name"].GetString()
29
+ self.sensor_group_name = parameters["sensor_group_name"].GetString()
30
+ self.debug_output = parameters["debug_output"].GetBool()
31
+ self.debug_output_filename = parameters["debug_output_filename"].GetString()
32
+
33
+ if model.HasModelPart(self.sensor_group_name):
34
+ raise RuntimeError(f"The sensor model part name \"{self.sensor_group_name}\" already exists. Please provide a different \"sensor_group_name\".")
35
+ self.sensor_model_part = model.CreateModelPart(self.sensor_group_name)
36
+
37
+ # this dummy component data view is used to create the proper sensor group within the optimization problem.
38
+ ComponentDataView(self.sensor_group_name, self.optimization_problem)
39
+
40
+ def ImportModelPart(self) -> None:
41
+ self.domain_model_part = self.model[self.domain_model_part_name]
42
+
43
+ if self.debug_output:
44
+ vtu_output: Kratos.VtuOutput = Kratos.VtuOutput(self.domain_model_part)
45
+ vtu_output.PrintOutput(self.debug_output_filename)
46
+
47
+ self.list_of_sensors = CreateSensors(self.sensor_model_part, self.domain_model_part, self.parameters["list_of_sensors"].values())
48
+
49
+ # add the list of sensors to optimization problem
50
+ sensor_group_data = ComponentDataView(self.sensor_group_name, self.optimization_problem)
51
+ sensor_group_data.SetDataBuffer(1)
52
+
53
+ SetSensors(sensor_group_data, self.list_of_sensors)
54
+
55
+ def GetModelPart(self) -> Kratos.ModelPart:
56
+ return self.sensor_model_part
57
+
58
+
@@ -0,0 +1,41 @@
1
+ import abc
2
+
3
+ import KratosMultiphysics as Kratos
4
+
5
+ from KratosMultiphysics.analysis_stage import AnalysisStage
6
+ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
7
+
8
+ class ResponseSensitivityAnalysis(AnalysisStage, abc.ABC):
9
+ @abc.abstractmethod
10
+ def CalculateGradient(self, response_function: Kratos.AdjointResponseFunction) -> None:
11
+ """Calculate the gradient using the provided adjoint response function.
12
+
13
+ This method calculate all the sensitivities using the given adjoint response function.
14
+
15
+ Args:
16
+ response_function (Kratos.AdjointResponseFunction): Adjoint response function to be used for sensitivity computation
17
+ """
18
+ pass
19
+
20
+ def GetGradient(self, sensitivity_variable: SupportedSensitivityFieldVariableTypes, gradient_tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None:
21
+ """Returns the gradients in the domain represented by gradient_tensor_adaptor tensor adaptor.
22
+
23
+ Args:
24
+ sensitivity_variable (SupportedSensitivityFieldVariableTypes): Sensitivity variable
25
+ gradient_tensor_adaptor (Kratos.TensorAdaptors.DoubleTensorAdaptor): TensorAdaptor to hold the gradients.
26
+ """
27
+ if isinstance(gradient_tensor_adaptor.GetContainer(), Kratos.NodesArray):
28
+ Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(gradient_tensor_adaptor, sensitivity_variable, copy=False).CollectData()
29
+ else:
30
+ Kratos.TensorAdaptors.VariableTensorAdaptor(gradient_tensor_adaptor, sensitivity_variable, copy=False).CollectData()
31
+
32
+ def GetProcessesOrder(self) -> 'list[str]':
33
+ """The order of execution of the process categories.
34
+
35
+ This defines the order of execution of the processes defined under "processes"
36
+ in either "kratos_process" or "optimization_data_processes".
37
+
38
+ Returns:
39
+ list[str]: List of strings for process categories.
40
+ """
41
+ return ["auxiliary_processes", "output_processes"]
@@ -0,0 +1,34 @@
1
+ import abc
2
+ import KratosMultiphysics as Kratos
3
+
4
+ class ResponseSensitivityInterface(abc.ABC):
5
+ @abc.abstractmethod
6
+ def SetResponseFunction(self, response_function: Kratos.AdjointResponseFunction) -> None:
7
+ """Set the response function to compute the sensitivities using adjoint method.
8
+
9
+ Args:
10
+ response_function (Kratos.AdjointResponseFunction): Response function to be used to compute the sensitivities.
11
+ """
12
+ pass
13
+
14
+ @abc.abstractmethod
15
+ def GetResponseFunction(self) -> Kratos.AdjointResponseFunction:
16
+ """Returns the response function used to compute the sensitivities.
17
+
18
+ Returns:
19
+ Kratos.AdjointResponseFunction: Adjoint response function used in adjoint based sensitivity computation.
20
+ """
21
+ pass
22
+
23
+ @abc.abstractmethod
24
+ def GetSensitivityModelPart(self) -> Kratos.ModelPart:
25
+ """Returns the model part used on which the sensitivities are computed.
26
+
27
+ This is the model part on which the sensitivities are computed, not the model part on which
28
+ the adjoint solution is computed.
29
+
30
+ Returns:
31
+ Kratos.ModelPart: Sensitivity model part on which the sensitivities are computed.
32
+ """
33
+ pass
34
+
@@ -0,0 +1,50 @@
1
+ import KratosMultiphysics as Kratos
2
+ import KratosMultiphysics.SystemIdentificationApplication as KratosSI
3
+ from KratosMultiphysics.StructuralMechanicsApplication.structural_mechanics_adjoint_static_solver import StructuralMechanicsAdjointStaticSolver
4
+ from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.response_sensitivity_interface import ResponseSensitivityInterface
5
+
6
+ class SensorSensitivityAdjointStaticSolver(StructuralMechanicsAdjointStaticSolver, ResponseSensitivityInterface):
7
+ def __init__(self, model: Kratos.Model, custom_settings: Kratos.Parameters):
8
+ super().__init__(model, custom_settings)
9
+ self.sensitivity_builder_initialized = False
10
+
11
+ default_response_function_settings = Kratos.Parameters("""{
12
+ "perturbation_size" : 1e-8,
13
+ "adapt_perturbation_size": true
14
+ }""")
15
+ self.settings["response_function_settings"].ValidateAndAssignDefaults(default_response_function_settings)
16
+
17
+ def Initialize(self) -> None:
18
+ model_part = self.GetComputingModelPart()
19
+
20
+ response_function_settings: Kratos.Parameters = self.settings["response_function_settings"]
21
+ model_part.ProcessInfo[KratosSI.PERTURBATION_SIZE] = response_function_settings["perturbation_size"].GetDouble()
22
+ model_part.ProcessInfo[KratosSI.ADAPT_PERTURBATION_SIZE] = response_function_settings["adapt_perturbation_size"].GetBool()
23
+
24
+ # create sensitivity builder
25
+ self.sensitivity_builder = Kratos.SensitivityBuilder(self.settings["sensitivity_settings"], self.main_model_part, None)
26
+
27
+ # skip calling Initialize of StructuralMechanicsAdjointStaticSolver and call the its base class Initialize
28
+ super(StructuralMechanicsAdjointStaticSolver, self).Initialize()
29
+
30
+ Kratos.Logger.PrintInfo(self.__class__.__name__, "Finished initialization.")
31
+
32
+ def SetResponseFunction(self, response_function: Kratos.AdjointResponseFunction) -> None:
33
+ self.response_function = response_function
34
+ self.sensitivity_builder.SetResponseFunction(response_function)
35
+ self._GetScheme().SetResponseFunction(response_function)
36
+ if not self.sensitivity_builder_initialized:
37
+ self.sensitivity_builder.Initialize()
38
+ self.sensitivity_builder_initialized = True
39
+
40
+ def GetResponseFunction(self) -> Kratos.AdjointResponseFunction:
41
+ return self._GetScheme().GetResponseFunction()
42
+
43
+ def GetSensitivityModelPart(self) -> Kratos.ModelPart:
44
+ return self.main_model_part.GetSubModelPart(self.settings["sensitivity_settings"]["sensitivity_model_part_name"].GetString())
45
+
46
+ def SolveSolutionStep(self) -> bool:
47
+ return super(StructuralMechanicsAdjointStaticSolver, self).SolveSolutionStep()
48
+
49
+ def _CreateScheme(self):
50
+ return Kratos.ResidualBasedAdjointStaticScheme(None)
@@ -0,0 +1,52 @@
1
+ import KratosMultiphysics as Kratos
2
+ import KratosMultiphysics.SystemIdentificationApplication as KratosSI
3
+
4
+ from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.response_sensitivity_analysis import ResponseSensitivityAnalysis
5
+ from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.sensor_sensitivity_adjoint_static_solver import SensorSensitivityAdjointStaticSolver
6
+
7
+ def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _):
8
+ return SystemIdentificationStaticAnalysis(model, parameters["settings"])
9
+
10
+ class SystemIdentificationStaticAnalysis(ResponseSensitivityAnalysis):
11
+ def _CreateSolver(self) -> SensorSensitivityAdjointStaticSolver:
12
+ return SensorSensitivityAdjointStaticSolver(self.model, self.project_parameters["solver_settings"])
13
+
14
+ def _GetSimulationName(self) -> str:
15
+ return "::[SystemIdentificationAnalysis]:: "
16
+
17
+ def CalculateGradient(self, response_function: Kratos.AdjointResponseFunction) -> None:
18
+ self._GetSolver().SetResponseFunction(response_function)
19
+ self.InitializeSolutionStep()
20
+ response_function.InitializeSolutionStep()
21
+ self._GetSolver().SolveSolutionStep()
22
+ response_function.FinalizeSolutionStep()
23
+ self.FinalizeSolutionStep()
24
+ self.OutputSolutionStep()
25
+
26
+ def PrintAnalysisStageProgressInformation(self):
27
+ process_info = self._GetSolver().GetComputingModelPart().ProcessInfo
28
+ Kratos.Logger.PrintInfo(self._GetSimulationName(), f"Step {process_info[Kratos.STEP]}: Computed sensitivities for response \"{process_info[KratosSI.SENSOR_NAME]}\" using \"{process_info[KratosSI.TEST_ANALYSIS_NAME]}\" analysis.")
29
+
30
+ if __name__ == "__main__":
31
+ from sys import argv
32
+
33
+ if len(argv) > 2:
34
+ err_msg = 'Too many input arguments!\n'
35
+ err_msg += 'Use this script in the following way:\n'
36
+ err_msg += '- With default ProjectParameters (read from "ProjectParameters.json"):\n'
37
+ err_msg += ' "python3 structural_mechanics_analysis.py"\n'
38
+ err_msg += '- With custom ProjectParameters:\n'
39
+ err_msg += ' "python3 structural_mechanics_analysis.py CustomProjectParameters.json"\n'
40
+ raise Exception(err_msg)
41
+
42
+ if len(argv) == 2: # ProjectParameters is being passed from outside
43
+ project_parameters_file_name = argv[1]
44
+ else: # using default name
45
+ project_parameters_file_name = "ProjectParameters.json"
46
+
47
+ with open(project_parameters_file_name,'r') as parameter_file:
48
+ parameters = Kratos.Parameters(parameter_file.read())
49
+
50
+ model = Kratos.Model()
51
+ simulation = SystemIdentificationStaticAnalysis(model, parameters)
52
+ simulation.Run()