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,222 @@
1
+ # | / |
2
+ # ' / __| _` | __| _ \ __|
3
+ # . \ | ( | | ( |\__ `
4
+ # _|\_\_| \__,_|\__|\___/ ____/
5
+ # Multi-Physics
6
+ #
7
+ # License: BSD License
8
+ # license: OptimizationApplication/license.txt
9
+ #
10
+ # Main authors: Suneth Warnakulasuriya
11
+ #
12
+
13
+ import time as timer
14
+ import datetime
15
+ import KratosMultiphysics as Kratos
16
+ from functools import wraps
17
+ import typing
18
+
19
+
20
+ def AddFileLoggerOutput(logger_file_name):
21
+ logger_file = Kratos.FileLoggerOutput(logger_file_name)
22
+ default_severity = Kratos.Logger.GetDefaultOutput().GetSeverity()
23
+ Kratos.Logger.GetDefaultOutput().SetSeverity(Kratos.Logger.Severity.WARNING)
24
+ Kratos.Logger.AddOutput(logger_file)
25
+
26
+ return default_severity, logger_file
27
+
28
+ def RemoveFileLoggerOutput(default_severity, logger_file):
29
+ Kratos.Logger.Flush()
30
+ Kratos.Logger.RemoveOutput(logger_file)
31
+ Kratos.Logger.GetDefaultOutput().SetSeverity(default_severity)
32
+
33
+ class FileLogger:
34
+ """@brief A context responsible for managing the lifetime of logger files."""
35
+ def __init__(self, logger_file_name: str):
36
+ self.__logger_file_name = logger_file_name
37
+
38
+ def __enter__(self):
39
+ self.__default_severity, self.__logger_file = AddFileLoggerOutput(self.__logger_file_name)
40
+
41
+ def __exit__(self, exit_type, exit_value, exit_traceback):
42
+ RemoveFileLoggerOutput(self.__default_severity, self.__logger_file)
43
+
44
+ class TimeLogger:
45
+ """@brief A context responsible for outputting execution times."""
46
+ def __init__(self, topic: str, entry_msg: str , exit_msg: str, end_new_line: bool=True):
47
+ self.topic = topic
48
+ self.entry_msg = entry_msg
49
+ self.exit_msg = exit_msg
50
+ self.start_time = None
51
+ self.end_new_line = end_new_line
52
+
53
+ def __enter__(self):
54
+ if self.entry_msg is not None:
55
+ Kratos.Logger.PrintInfo(self.topic, self.entry_msg)
56
+ self.start_time = timer.time()
57
+
58
+ def __exit__(self, exit_type, exit_value, exit_traceback):
59
+ if self.exit_msg is not None:
60
+ elapsed_time = timer.time() - self.start_time
61
+ if self.end_new_line:
62
+ Kratos.Logger.PrintInfo(self.topic, "{:s} - [ Elapsed time: {:s} ]".format(self.exit_msg, str(datetime.timedelta(seconds=round(elapsed_time))))+"\n")
63
+ else:
64
+ Kratos.Logger.PrintInfo(self.topic, "{:s} - [ Elapsed time: {:s} ]".format(self.exit_msg, str(datetime.timedelta(seconds=round(elapsed_time)))))
65
+
66
+ class OptimizationAlgorithmTimeLogger:
67
+ """@brief A context responsible for outputting execution times."""
68
+ def __init__(self, optimizer_name: str, optimization_itr: int):
69
+ self.start_time = None
70
+ self.optimization_itr = optimization_itr
71
+ self.optimizer_name = optimizer_name
72
+
73
+ def __enter__(self):
74
+ self.start_time = timer.time()
75
+
76
+ def __exit__(self, exit_type, exit_value, exit_traceback):
77
+
78
+ current_time = timer.time()
79
+ elapsed_time = current_time - self.start_time
80
+ elapsed_time_string = str(datetime.timedelta(seconds=round(elapsed_time)))
81
+
82
+ iteration_text = f"{self.optimizer_name} EoF Iteration {self.optimization_itr}"
83
+ iteration_output = f"{'#'} {iteration_text} [Elapsed Time: {elapsed_time_string}] {'#'}"
84
+
85
+ divided_line = len(iteration_output) * '#'
86
+
87
+ to_print = f"{divided_line}\n{iteration_output}\n{divided_line}\n"
88
+
89
+ Kratos.Logger.PrintInfo(to_print)
90
+
91
+ class OptimizationAnalysisTimeLogger:
92
+
93
+ def __enter__(self):
94
+ start_text = "Optimization Start"
95
+
96
+ self.start_time = datetime.datetime.now()
97
+ start_time_string = self.start_time.strftime("%Y-%m-%d %H:%M:%S")
98
+
99
+ time_string = f"** {start_time_string} **"
100
+ separator_string = len(time_string) * '*'
101
+ center_string = f"**{start_text.center(len(str(time_string))-4)}**"
102
+ final_string = f"{separator_string}\n{center_string}\n{time_string}\n{separator_string}"
103
+
104
+ Kratos.Logger.PrintInfo(final_string)
105
+
106
+ def __exit__(self, exit_type, exit_value, exit_traceback):
107
+
108
+ end_text = "Optimization End"
109
+
110
+ end_time = datetime.datetime.now()
111
+ end_time_string = end_time.strftime("%Y-%m-%d %H:%M:%S")
112
+
113
+ elapsed_time = end_time - self.start_time
114
+ elapsed_time_string = str(datetime.timedelta(seconds=round(elapsed_time.total_seconds())))
115
+
116
+ time_string = f"** {end_time_string} [Elapsed Time: {elapsed_time_string}] **"
117
+ separator_string = len(time_string) * '*'
118
+ center_string = f"**{end_text.center(len(str(time_string))-4)}**"
119
+ final_string = f"{separator_string}\n{center_string}\n{time_string}\n{separator_string}"
120
+
121
+ Kratos.Logger.PrintInfo(final_string)
122
+
123
+ def DictLogger(title: str, data: dict):
124
+
125
+ # First do the formatting and converting to strings
126
+ for key, value in data.items():
127
+ if isinstance(value, (float, int)):
128
+ if abs(value) >= 1e6 or abs(value) < 1e-6:
129
+ data[key] = "{:.6e}".format(value)
130
+ else:
131
+ data[key] = "{:.6f}".format(value)
132
+
133
+ # Determine the maximum length of labels
134
+ max_label_len = max(len(str(label)) for label in data.keys())
135
+ max_value_len = max(len(str(value)) for value in data.values())
136
+
137
+ title_len = len(str(title)) + 8
138
+
139
+ # Calculate the row width
140
+ if title_len > max_label_len + max_value_len + 7:
141
+ row_width = title_len
142
+ max_value_len = row_width - max_label_len - 7
143
+ else:
144
+ row_width = max_label_len + max_value_len + 7
145
+
146
+ # Create format strings for the labels and values
147
+ label_format = f"| {{:<{max_label_len}}} |"
148
+
149
+ # Build the table
150
+ table = '-' * row_width + "\n"
151
+ table += f"|{str(title).center(row_width - 2)}|\n"
152
+ table += '-' * row_width + "\n"
153
+
154
+ # Add the data to the table
155
+ for label, value in data.items():
156
+ table += f"{label_format.format(label)} {value:>{max_value_len}} |\n"
157
+
158
+ table += '-' * row_width
159
+
160
+ # now print
161
+ Kratos.Logger.PrintInfo(table)
162
+
163
+ def ListLogger(title: str, data: 'list[tuple[str, typing.Union[int, float, str]]]'):
164
+ # First do the formatting and converting to strings
165
+ sting_data: 'list[tuple[str, typing.Union[int, float, str]]]' = []
166
+ for key, value in data:
167
+ if isinstance(value, (float, int)):
168
+ if abs(value) >= 1e6 or abs(value) < 1e-6:
169
+ sting_data.append((key, "{:.6e}".format(value)))
170
+ else:
171
+ sting_data.append((key, "{:.6f}".format(value)))
172
+
173
+ # Determine the maximum length of labels
174
+ max_label_len = max(len(str(label)) for label, _ in data)
175
+ max_value_len = max(len(str(value)) for _, value in data)
176
+
177
+ title_len = len(str(title)) + 8
178
+
179
+ # Calculate the row width
180
+ if title_len > max_label_len + max_value_len + 7:
181
+ row_width = title_len
182
+ max_value_len = row_width - max_label_len - 7
183
+ else:
184
+ row_width = max_label_len + max_value_len + 7
185
+
186
+ # Create format strings for the labels and values
187
+ label_format = f"| {{:<{max_label_len}}} |"
188
+
189
+ # Build the table
190
+ table = '-' * row_width + "\n"
191
+ table += f"|{str(title).center(row_width - 2)}|\n"
192
+ table += '-' * row_width + "\n"
193
+
194
+ # Add the data to the table
195
+ for label, value in data:
196
+ table += f"{label_format.format(label)} {value:>{max_value_len}} |\n"
197
+
198
+ table += '-' * row_width
199
+
200
+ # now print
201
+ Kratos.Logger.PrintInfo(table)
202
+
203
+ def time_decorator(arg1=None, arg2=None, methodName=None):
204
+ def inner_func(func):
205
+ @wraps(func)
206
+ def wrapper(self,*args, **kwargs):
207
+ start_time = timer.perf_counter()
208
+ if arg1:
209
+ Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: {arg1}")
210
+ result = func(self,*args, **kwargs)
211
+ end_time = timer.perf_counter()
212
+ elapsed_time = end_time - start_time
213
+ if arg2:
214
+ Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: {arg2} - [ Elapsed time: {datetime.timedelta(seconds=round(elapsed_time))}] \n")
215
+ elif methodName:
216
+ method_to_call = getattr(self, methodName)
217
+ Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: {method_to_call()} finished - [ Elapsed time: {datetime.timedelta(seconds=round(elapsed_time))}] \n")
218
+ else:
219
+ Kratos.Logger.Print(f"{func.__qualname__.split('.')[0]}::{func.__name__}: Finished - [ Elapsed time: {datetime.timedelta(seconds=round(elapsed_time))}] \n")
220
+ return result
221
+ return wrapper
222
+ return inner_func
@@ -0,0 +1,117 @@
1
+ from typing import Any
2
+ from enum import Enum
3
+ import KratosMultiphysics as Kratos
4
+ import KratosMultiphysics.OptimizationApplication as KratosOA
5
+
6
+ class ModelPartOperation:
7
+ class OperationType(Enum):
8
+ UNION = 1,
9
+ INTERSECT = 2
10
+
11
+ def __init__(self, model: Kratos.Model, operation_type: OperationType, suggested_model_part_name: str, list_of_operation_model_part_full_names: 'list[str]', add_neighbours: bool) -> None:
12
+ self.model = model
13
+ self.operation_type = operation_type
14
+ self.suggested_model_part_name = suggested_model_part_name
15
+ self.list_of_operation_model_part_full_names = sorted(list(set(list_of_operation_model_part_full_names)))
16
+ self.add_neighbours = add_neighbours
17
+
18
+ if len(list_of_operation_model_part_full_names) == 0:
19
+ raise RuntimeError("No operating model part names are provided.")
20
+
21
+ if suggested_model_part_name.find("#") != -1 or any([mp_name.find("#") != -1 for mp_name in list_of_operation_model_part_full_names]):
22
+ # find '#' in the model part names which is not allowed.
23
+ raise RuntimeError(f"The model part names cannot contain '#' character. Parsed model part names are as followings:\n\t suggested model part name: \"{suggested_model_part_name}\"\n\toperation model part names:\n\t" + "\n\t\t".join(list_of_operation_model_part_full_names))
24
+
25
+ # set the root model part. This needs to always exist.
26
+ self.root_model_part = self.model[self.list_of_operation_model_part_full_names[0].split(".")[0]]
27
+ self.status_msg = ""
28
+
29
+ def GetRootModelPart(self) -> Kratos.ModelPart:
30
+ return self.root_model_part
31
+
32
+ def GetModelPartFullName(self) -> str:
33
+ # check whether is there a need to perform binary operations
34
+ if self.operation_type == ModelPartOperation.OperationType.UNION or self.operation_type == ModelPartOperation.OperationType.INTERSECT:
35
+ if len(self.list_of_operation_model_part_full_names) == 1:
36
+ # all the operation model parts are the same, hence no need of doing an operation.
37
+ self.status_msg = ""
38
+ return self.list_of_operation_model_part_full_names[0]
39
+
40
+ # now check in the status messages of the root model part whether this operation is already added.
41
+ status_msg_prefix = "ModelPartUtilities_created#"
42
+ status_msg_suffix = f"#{self.operation_type.name}#{self.add_neighbours:d}#" + "#".join(self.list_of_operation_model_part_full_names)
43
+ status_msg_log = KratosOA.OptAppModelPartUtils.GetModelPartStatusLog(self.GetRootModelPart())
44
+ for status_msg in status_msg_log:
45
+ if status_msg.startswith(status_msg_prefix) and status_msg.endswith(status_msg_suffix):
46
+ # found the same operation done on a different model part, hence sending that name
47
+ self.status_msg = status_msg
48
+ full_model_part_name = f"{self.GetRootModelPart().FullName()}.{status_msg.split('#')[1]}"
49
+ Kratos.Logger.PrintInfo("ModelPartUtilities", f"Using \"{full_model_part_name}\" with the same operation instead of suggested model part with name = \"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}\".")
50
+ return full_model_part_name
51
+
52
+ # it is not already called for creation. Then put that in the status msg.
53
+ if self.root_model_part.HasSubModelPart(self.suggested_model_part_name):
54
+ # this means, it already has a model part with suggested name, but
55
+ # it does not match the operation identifier. So throw an error
56
+ raise RuntimeError(f"Found an already existing submodel part named \"{self.suggested_model_part_name}\" in {self.root_model_part.FullName()} without the required operation identifier = \"{status_msg_suffix}\".")
57
+
58
+ self.status_msg = f"{status_msg_prefix}{self.suggested_model_part_name}{status_msg_suffix}"
59
+ KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.GetRootModelPart(), self.status_msg)
60
+ return f"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}"
61
+
62
+ def GetModelPart(self) -> Kratos.ModelPart:
63
+ model_part_name = self.GetModelPartFullName()
64
+ if self.status_msg == "" or self.model.HasModelPart(model_part_name):
65
+ # if it is already there, that means it is already created. Hence return it or
66
+ # if the self.status_msg == "" means, there is no need to do any model part operations.
67
+ # therefore the model part should exist already.
68
+ return self.model[model_part_name]
69
+ else:
70
+ # the model part with the required operation not found. Hence creating it.
71
+ sub_model_part = self.model.CreateModelPart(model_part_name)
72
+ # now fill the submodel part
73
+ operation_model_parts = [self.model[name] for name in self.list_of_operation_model_part_full_names]
74
+ if self.operation_type == ModelPartOperation.OperationType.UNION:
75
+ Kratos.ModelPartOperationUtilities.Union(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours)
76
+ elif self.operation_type == ModelPartOperation.OperationType.INTERSECT:
77
+ Kratos.ModelPartOperationUtilities.Intersect(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours)
78
+
79
+ Kratos.Logger.PrintInfo("ModelPartUtilities", f"Created sub model part \"{sub_model_part.FullName()}\".")
80
+
81
+ return sub_model_part
82
+
83
+ class ModelPartUtilities:
84
+ @staticmethod
85
+ def __GenerateUniqueIdentifier(prefix: str, list_of_names: 'list[str]', add_neighbours: bool) -> str:
86
+ if not all([name.find("#") == -1 for name in list_of_names]):
87
+ raise RuntimeError(f"The provided model part names has \"#\" which is invalid. Please remove all occurances of \"#\" character. Provided model part names:\n\t" + "\n\t".join(list_of_names))
88
+
89
+ sorted_names = sorted(list_of_names)
90
+ post_fix = "IN" if add_neighbours else "EN"
91
+ return (f"{prefix}_{post_fix}_" + "_".join(sorted_names)).replace(".", "-")
92
+
93
+ @staticmethod
94
+ def GetMergedMap(input_dict: 'dict[Any, KratosOA.CollectiveExpression]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]':
95
+ result: 'dict[Any, Kratos.ModelPart]' = {}
96
+ for k, v in input_dict.items():
97
+ merging_model_part_names = [container_expression.GetModelPart().FullName() for container_expression in v.GetContainerExpressions()]
98
+
99
+ if not merging_model_part_names:
100
+ raise RuntimeError("Merging requires atleast one model part.")
101
+
102
+ uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("UNION", merging_model_part_names, add_neghbours)
103
+ merged_model_part = ModelPartOperation(v.GetContainerExpressions()[0].GetModelPart().GetModel(), ModelPartOperation.OperationType.UNION, uniqe_identifier_name, merging_model_part_names, add_neghbours).GetModelPart()
104
+ result[k] = merged_model_part
105
+
106
+ return result
107
+
108
+ @staticmethod
109
+ def GetIntersectedMap(main_model_part: Kratos.ModelPart, input_dict: 'dict[Any, Kratos.ModelPart]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]':
110
+ result: 'dict[Any, Kratos.ModelPart]' = {}
111
+ for k, v in input_dict.items():
112
+ intersecting_model_part_names = [main_model_part.FullName(), v.FullName()]
113
+ uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("INTERSECT", intersecting_model_part_names, add_neghbours)
114
+ intersected_model_part = ModelPartOperation(main_model_part.GetModel(), ModelPartOperation.OperationType.INTERSECT, uniqe_identifier_name, intersecting_model_part_names, add_neghbours).GetModelPart()
115
+ result[k] = intersected_model_part
116
+
117
+ return result
@@ -0,0 +1,173 @@
1
+ import KratosMultiphysics as Kratos
2
+ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
3
+ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
4
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger
5
+ from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
6
+ import numpy
7
+
8
+ import math
9
+
10
+ def CreateLineSearch(parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
11
+ type = parameters["type"].GetString()
12
+ if type == "const_step":
13
+ return ConstStep(parameters, optimization_problem)
14
+ elif type == "BB_step":
15
+ return BBStep(parameters, optimization_problem)
16
+ elif type == "QNBB_step":
17
+ return QNBBStep(parameters, optimization_problem)
18
+ else:
19
+ raise RuntimeError(f"CreateConvergenceCriteria: unsupported convergence type {type}.")
20
+
21
+ class ConstStep():
22
+ @classmethod
23
+ def GetDefaultParameters(cls):
24
+ return Kratos.Parameters("""{
25
+ "type" : "const_step",
26
+ "init_step" : 0,
27
+ "gradient_scaling": ": inf_norm"
28
+ }""")
29
+
30
+ def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
31
+ parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
32
+ self._init_step = parameters["init_step"].GetDouble()
33
+ self._optimization_problem = optimization_problem
34
+ self._gradient_scaling = parameters["gradient_scaling"].GetString()
35
+ self.unscaled_step = self._init_step
36
+
37
+ def ComputeScaleFactor(self) -> float:
38
+ algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
39
+
40
+ if not algorithm_buffered_data.HasValue("search_direction"):
41
+ raise RuntimeError(f"Algorithm data does not contain computed \"search_direction\".\nData:\n{algorithm_buffered_data}" )
42
+
43
+ search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data["search_direction"]
44
+ if self._gradient_scaling == "inf_norm":
45
+ return numpy.max(numpy.abs(search_direction.data))
46
+ elif self._gradient_scaling == "l2_norm":
47
+ return numpy.linalg.norm(search_direction.data)
48
+ elif self._gradient_scaling == "none":
49
+ return 1.0
50
+ else:
51
+ raise RuntimeError("\"gradient_scaling\" has unknown type.")
52
+
53
+ @time_decorator()
54
+ def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
55
+ norm = self.ComputeScaleFactor()
56
+ if not math.isclose(norm, 0.0, abs_tol=1e-16):
57
+ self.step = self._init_step / norm
58
+ else:
59
+ self.step = self._init_step
60
+
61
+ DictLogger("Line Search info",self.GetInfo())
62
+
63
+ algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
64
+ step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data["search_direction"])
65
+ step.data[:] = self.step
66
+ return step
67
+
68
+ def GetInfo(self) -> dict:
69
+ info = {'type': 'constant',
70
+ 'unscaled_step': self.unscaled_step,
71
+ 'scaled_step': self.step}
72
+ return info
73
+
74
+ class BBStep(ConstStep):
75
+ @classmethod
76
+ def GetDefaultParameters(cls):
77
+ return Kratos.Parameters("""{
78
+ "type" : "BB_step",
79
+ "init_step" : 0,
80
+ "max_step" : 0,
81
+ "gradient_scaling" : "inf_norm"
82
+ }""")
83
+
84
+ def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
85
+ parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
86
+ self._init_step = parameters["init_step"].GetDouble()
87
+ self._max_step = parameters["max_step"].GetDouble()
88
+ self._optimization_problem = optimization_problem
89
+ self._gradient_scaling = parameters["gradient_scaling"].GetString()
90
+
91
+ @time_decorator()
92
+ def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
93
+ algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
94
+ norm = self.ComputeScaleFactor()
95
+ if math.isclose(norm, 0.0, abs_tol=1e-16):
96
+ norm = 1.0
97
+ if self._optimization_problem.GetStep() == 0:
98
+ self.step = self._init_step / norm
99
+ else:
100
+ current_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 0)
101
+ previous_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 1)
102
+ y = previous_search_direction.data - current_search_direction.data
103
+ d: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("control_field_update", 1)
104
+ dy = numpy.inner(d.data[:].ravel(), y.ravel())
105
+ dd = numpy.inner(d.data[:].ravel(), d.data[:].ravel())
106
+ if math.isclose(dy, 0.0, abs_tol=1e-16):
107
+ self.step = self._max_step / norm
108
+ else:
109
+ self.step = abs( dd / dy )
110
+
111
+ if self.step > self._max_step / norm:
112
+ self.step = self._max_step / norm
113
+
114
+ DictLogger("Line Search info",self.GetInfo())
115
+
116
+ algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
117
+ step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data["search_direction"])
118
+ step.data[:] = self.step
119
+ return step
120
+
121
+ def GetInfo(self) -> dict:
122
+ info = {'type': 'BB_step',
123
+ 'step': self.step,
124
+ 'max_step': self._max_step,
125
+ 'init_step': self._init_step}
126
+
127
+ return info
128
+
129
+ class QNBBStep(BBStep):
130
+ @time_decorator()
131
+ def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor:
132
+ algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData()
133
+ norm = self.ComputeScaleFactor()
134
+ if math.isclose(norm, 0.0, abs_tol=1e-16):
135
+ norm = 1.0
136
+ self.step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data.GetValue("search_direction", 0), perform_store_data_recursively=False)
137
+ self.step.data[:] = 0.0
138
+ if not algorithm_buffered_data.HasValue("step_size"):
139
+ algorithm_buffered_data["step_size"] = self.step
140
+
141
+ if self._optimization_problem.GetStep() == 0:
142
+ self.step.data[:] = self._init_step / norm
143
+ else:
144
+ current_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 0)
145
+ previous_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 1)
146
+ y = previous_search_direction.data - current_search_direction.data
147
+ d: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("control_field_update", 1)
148
+ d = d.data[:]
149
+ for i in range(len(y)):
150
+ dy = numpy.dot(d[i], y[i])
151
+ dd = numpy.dot(d[i], d[i])
152
+
153
+ if math.isclose(dy, 0.0, abs_tol=1e-16):
154
+ self.step.data[i] = self._max_step / norm
155
+ else:
156
+ self.step.data[i] = abs( dd / dy )
157
+
158
+ if isinstance(d[i], (float, int, numpy.float64)) and self.step.data[i] > self._max_step / norm:
159
+ self.step.data[i] = self._max_step / norm
160
+ elif isinstance(d[i], (numpy.ndarray)) and self.step.data[i][0] > self._max_step / norm:
161
+ self.step.data[i] = self._max_step / norm
162
+
163
+ DictLogger("Line Search info",self.GetInfo())
164
+ self.step.StoreData()
165
+ return self.step
166
+
167
+ def GetInfo(self) -> dict:
168
+ info = {'type': 'QNBB_step',
169
+ # 'max scaled_step': self.step.max(),
170
+ 'max_step': self._max_step,
171
+ 'init_step': self._init_step}
172
+
173
+ return info