KratosShapeOptimizationApplication 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 (69) hide show
  1. KratosMultiphysics/.libs/KratosShapeOptimizationApplication.so +0 -0
  2. KratosMultiphysics/.libs/libKratosShapeOptimizationCore.dylib +0 -0
  3. KratosMultiphysics/ShapeOptimizationApplication/TemplateMainKratosShapeOptimization.py +31 -0
  4. KratosMultiphysics/ShapeOptimizationApplication/__init__.py +19 -0
  5. KratosMultiphysics/ShapeOptimizationApplication/algorithms/__init__.py +0 -0
  6. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_base.py +31 -0
  7. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_bead_optimization.py +412 -0
  8. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_factory.py +62 -0
  9. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_gradient_projection.py +317 -0
  10. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_penalized_projection.py +225 -0
  11. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +580 -0
  12. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_shape_fraction_optimization.py +622 -0
  13. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_steepest_descent.py +255 -0
  14. KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_trust_region.py +657 -0
  15. KratosMultiphysics/ShapeOptimizationApplication/analyzers/__init__.py +0 -0
  16. KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_base.py +30 -0
  17. KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_empty.py +21 -0
  18. KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_factory.py +310 -0
  19. KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_internal.py +155 -0
  20. KratosMultiphysics/ShapeOptimizationApplication/communicator_factory.py +259 -0
  21. KratosMultiphysics/ShapeOptimizationApplication/custom_ios/__init__.py +0 -0
  22. KratosMultiphysics/ShapeOptimizationApplication/custom_ios/wrl_io.py +82 -0
  23. KratosMultiphysics/ShapeOptimizationApplication/custom_ios/wrl_reader.py +119 -0
  24. KratosMultiphysics/ShapeOptimizationApplication/loggers/__init__.py +0 -0
  25. KratosMultiphysics/ShapeOptimizationApplication/loggers/data_logger_factory.py +199 -0
  26. KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_base.py +28 -0
  27. KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_gid.py +112 -0
  28. KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_unv.py +73 -0
  29. KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_vtk.py +96 -0
  30. KratosMultiphysics/ShapeOptimizationApplication/loggers/sensitivity_heatmap_logger.py +91 -0
  31. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_base.py +128 -0
  32. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_bead_optimization.py +79 -0
  33. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_gradient_projection.py +80 -0
  34. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_penalized_projection.py +79 -0
  35. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_relaxed_gradient_projection.py +108 -0
  36. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_shape_fraction_optimization.py +92 -0
  37. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_steepest_descent.py +64 -0
  38. KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_trust_region.py +100 -0
  39. KratosMultiphysics/ShapeOptimizationApplication/mapper_factory.py +100 -0
  40. KratosMultiphysics/ShapeOptimizationApplication/mapping/__init__.py +0 -0
  41. KratosMultiphysics/ShapeOptimizationApplication/mapping/in_plane_vertex_morphing_mapper.py +140 -0
  42. KratosMultiphysics/ShapeOptimizationApplication/mapping/sliding_vertex_morphing_mapper.py +378 -0
  43. KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/__init__.py +0 -0
  44. KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/mesh_controller_base.py +22 -0
  45. KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/mesh_controller_basic_updating.py +35 -0
  46. KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/mesh_controller_with_solver.py +237 -0
  47. KratosMultiphysics/ShapeOptimizationApplication/model_part_controller_factory.py +197 -0
  48. KratosMultiphysics/ShapeOptimizationApplication/optimizer_factory.py +235 -0
  49. KratosMultiphysics/ShapeOptimizationApplication/response_functions/__init__.py +0 -0
  50. KratosMultiphysics/ShapeOptimizationApplication/response_functions/airfoil_2d_responses.py +189 -0
  51. KratosMultiphysics/ShapeOptimizationApplication/response_functions/face_angle.py +140 -0
  52. KratosMultiphysics/ShapeOptimizationApplication/response_functions/mesh_based_packaging.py +70 -0
  53. KratosMultiphysics/ShapeOptimizationApplication/response_functions/packaging_response_base.py +156 -0
  54. KratosMultiphysics/ShapeOptimizationApplication/response_functions/plane_based_packaging.py +61 -0
  55. KratosMultiphysics/ShapeOptimizationApplication/response_functions/response_function_factory.py +40 -0
  56. KratosMultiphysics/ShapeOptimizationApplication/response_functions/surface_normal_shape_change.py +125 -0
  57. KratosMultiphysics/ShapeOptimizationApplication/response_functions/total_volume.py +56 -0
  58. KratosMultiphysics/ShapeOptimizationApplication/utilities/__init__.py +0 -0
  59. KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_math.py +443 -0
  60. KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_sensitivity_heatmap.py +235 -0
  61. KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_timer.py +47 -0
  62. KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_variable_utilities.py +54 -0
  63. kratosshapeoptimizationapplication-10.4.4.dist-info/METADATA +31 -0
  64. kratosshapeoptimizationapplication-10.4.4.dist-info/RECORD +69 -0
  65. kratosshapeoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
  66. kratosshapeoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
  67. kratosshapeoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
  68. kratosshapeoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
  69. kratosshapeoptimizationapplication.dylibs/libstdc++.6.dylib +0 -0
@@ -0,0 +1,657 @@
1
+ # ==============================================================================
2
+ # KratosShapeOptimizationApplication
3
+ #
4
+ # License: BSD License
5
+ # license: ShapeOptimizationApplication/license.txt
6
+ #
7
+ # Main authors: Baumgaertner Daniel, https://github.com/dbaumgaertner
8
+ #
9
+ # ==============================================================================
10
+
11
+
12
+ # Kratos Core and Apps
13
+ import KratosMultiphysics as KM
14
+ import KratosMultiphysics.ShapeOptimizationApplication as KSO
15
+
16
+ # Additional imports
17
+ from KratosMultiphysics.ShapeOptimizationApplication.algorithms.algorithm_base import OptimizationAlgorithm
18
+ from KratosMultiphysics.ShapeOptimizationApplication import mapper_factory
19
+ from KratosMultiphysics.ShapeOptimizationApplication.loggers import data_logger_factory
20
+ from KratosMultiphysics.ShapeOptimizationApplication.utilities import custom_math as cm
21
+ from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_timer import Timer
22
+ from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_variable_utilities import WriteDictionaryDataOnNodalVariable, ReadNodalVariableToList, WriteListToNodalVariable
23
+ import copy
24
+
25
+ # ==============================================================================
26
+ class AlgorithmTrustRegion(OptimizationAlgorithm):
27
+ # --------------------------------------------------------------------------
28
+ def __init__(self, optimization_settings, analyzer, communicator, model_part_controller):
29
+ default_algorithm_settings = KM.Parameters("""
30
+ {
31
+ "name" : "trust_region",
32
+ "max_step_length" : 1.0,
33
+ "step_length_tolerance" : 1e-3,
34
+ "step_length_reduction_factor" : 0.5,
35
+ "max_iterations" : 10,
36
+ "far_away_length" : 2.0,
37
+ "subopt_max_itr" : 50,
38
+ "subopt_tolerance" : 1e-10,
39
+ "bisectioning_max_itr" : 30,
40
+ "bisectioning_tolerance" : 1e-2,
41
+ "relative_tolerance" : 1e-12,
42
+ "obj_share_during_correction" : 1
43
+ }""")
44
+ self.algorithm_settings = optimization_settings["optimization_algorithm"]
45
+ self.algorithm_settings.RecursivelyValidateAndAssignDefaults(default_algorithm_settings)
46
+
47
+ self.optimization_settings = optimization_settings
48
+ self.mapper_settings = optimization_settings["design_variables"]["filter"]
49
+
50
+ self.analyzer = analyzer
51
+ self.communicator = communicator
52
+ self.model_part_controller = model_part_controller
53
+
54
+ self.design_surface = None
55
+ self.mapper = None
56
+ self.data_logger = None
57
+ self.optimization_utilities = None
58
+
59
+ self.objectives = optimization_settings["objectives"]
60
+ self.constraints = optimization_settings["constraints"]
61
+
62
+ self.optimization_model_part = model_part_controller.GetOptimizationModelPart()
63
+
64
+ # --------------------------------------------------------------------------
65
+ def CheckApplicability(self):
66
+ if self.objectives.size() > 1:
67
+ raise RuntimeError("Trust-region algorithm only supports one objective function!")
68
+
69
+ # --------------------------------------------------------------------------
70
+ def InitializeOptimizationLoop(self):
71
+ self.model_part_controller.Initialize()
72
+
73
+ self.analyzer.InitializeBeforeOptimizationLoop()
74
+
75
+ self.design_surface = self.model_part_controller.GetDesignSurface()
76
+
77
+ self.mapper = mapper_factory.CreateMapper(self.design_surface, self.design_surface, self.mapper_settings)
78
+ self.mapper.Initialize()
79
+ self.model_part_controller.InitializeDamping()
80
+
81
+ self.data_logger = data_logger_factory.CreateDataLogger(self.model_part_controller, self.communicator, self.optimization_settings)
82
+ self.data_logger.InitializeDataLogging()
83
+
84
+ self.optimization_utilities = KSO.OptimizationUtilities
85
+
86
+ # --------------------------------------------------------------------------
87
+ def RunOptimizationLoop(self):
88
+ timer = Timer()
89
+ timer.StartTimer()
90
+
91
+ for self.opt_iteration in range(1,self.algorithm_settings["max_iterations"].GetInt()+1):
92
+ KM.Logger.Print("")
93
+ KM.Logger.Print("===============================================================================")
94
+ KM.Logger.PrintInfo("ShapeOpt", timer.GetTimeStamp(), ": Starting optimization iteration ",self.opt_iteration)
95
+ KM.Logger.Print("===============================================================================\n")
96
+
97
+ timer.StartNewLap()
98
+
99
+ self.__InitializeNewShape()
100
+
101
+ self.__AnalyzeShape()
102
+
103
+ self.__PostProcessGradientsObtainedFromAnalysis()
104
+
105
+ len_obj, dir_obj, len_eqs, dir_eqs, len_ineqs, dir_ineqs = self.__ConvertAnalysisResultsToLengthDirectionFormat()
106
+
107
+ step_length = self.__DetermineMaxStepLength()
108
+
109
+ len_bar_obj, len_bar_eqs, len_bar_ineqs = self.__ExpressInStepLengthUnit(len_obj, len_eqs, len_ineqs, step_length)
110
+
111
+ dX_bar, process_details = self.__DetermineStep(len_bar_obj, dir_obj, len_bar_eqs, dir_eqs, len_bar_ineqs, dir_ineqs)
112
+
113
+ dX = self.__ComputeShapeUpdate(dX_bar, step_length)
114
+
115
+ values_to_be_logged = {}
116
+ values_to_be_logged["len_bar_obj"] = len_bar_obj
117
+ values_to_be_logged["len_bar_cons"] = self.__CombineConstraintDataToOrderedList(len_bar_eqs, len_bar_ineqs)
118
+ values_to_be_logged["step_length"] = step_length
119
+ values_to_be_logged["test_norm_dX_bar"] = process_details["test_norm_dX"]
120
+ values_to_be_logged["bi_itrs"] = process_details["bi_itrs"]
121
+ values_to_be_logged["bi_err"] = process_details["bi_err"]
122
+ values_to_be_logged["adj_len_bar_obj"] = process_details["adj_len_obj"]
123
+ values_to_be_logged["adj_len_bar_cons"] = self.__CombineConstraintDataToOrderedList(process_details["adj_len_eqs"], process_details["adj_len_ineqs"])
124
+ values_to_be_logged["norm_dX"] = cm.NormInf3D(dX)
125
+
126
+ self.__LogCurrentOptimizationStep(values_to_be_logged)
127
+
128
+ KM.Logger.Print("")
129
+ KM.Logger.PrintInfo("ShapeOpt", "Time needed for current optimization step = ", timer.GetLapTime(), "s")
130
+ KM.Logger.PrintInfo("ShapeOpt", "Time needed for total optimization so far = ", timer.GetTotalTime(), "s")
131
+
132
+ if self.__isAlgorithmConverged():
133
+ break
134
+
135
+ # --------------------------------------------------------------------------
136
+ def FinalizeOptimizationLoop(self):
137
+ self.analyzer.FinalizeAfterOptimizationLoop()
138
+ self.data_logger.FinalizeDataLogging()
139
+
140
+ # --------------------------------------------------------------------------
141
+ def __isAlgorithmConverged(self):
142
+
143
+ if self.opt_iteration > 1 :
144
+ # Check if maximum iterations were reached
145
+ if self.opt_iteration == self.algorithm_settings["max_iterations"].GetInt():
146
+ KM.Logger.Print("")
147
+ KM.Logger.PrintInfo("ShapeOpt", "Maximal iterations of optimization problem reached!")
148
+ return True
149
+
150
+ # Check for relative tolerance
151
+ relative_change_of_objective_value = self.data_logger.GetValues("rel_change_objective")[self.opt_iteration]
152
+ if abs(relative_change_of_objective_value) < self.algorithm_settings["relative_tolerance"].GetDouble():
153
+ KM.Logger.Print("")
154
+ KM.Logger.PrintInfo("ShapeOpt", "Optimization problem converged within a relative objective tolerance of ",self.algorithm_settings["relative_tolerance"].GetDouble(),"%.")
155
+ return True
156
+
157
+ # --------------------------------------------------------------------------
158
+ def __InitializeNewShape(self):
159
+ self.model_part_controller.UpdateTimeStep(self.opt_iteration)
160
+ self.model_part_controller.UpdateMeshAccordingInputVariable(KSO.SHAPE_UPDATE)
161
+ self.model_part_controller.SetReferenceMeshToMesh()
162
+
163
+ # --------------------------------------------------------------------------
164
+ def __AnalyzeShape(self):
165
+ self.communicator.initializeCommunication()
166
+
167
+ obj_id = self.objectives[0]["identifier"].GetString()
168
+ self.communicator.requestValueOf(obj_id)
169
+ self.communicator.requestGradientOf(obj_id)
170
+
171
+ for itr in range(self.constraints.size()):
172
+ con_id = self.constraints[itr]["identifier"].GetString()
173
+ self.communicator.requestValueOf(con_id)
174
+ self.communicator.requestGradientOf(con_id)
175
+
176
+ self.analyzer.AnalyzeDesignAndReportToCommunicator(self.optimization_model_part, self.opt_iteration, self.communicator)
177
+
178
+ # --------------------------------------------------------------------------
179
+ def __PostProcessGradientsObtainedFromAnalysis(self):
180
+ # Compute surface normals if required
181
+ if self.objectives[0]["project_gradient_on_surface_normals"].GetBool():
182
+ self.model_part_controller.ComputeUnitSurfaceNormals()
183
+ else:
184
+ for itr in range(self.constraints.size()):
185
+ if self.constraints[itr]["project_gradient_on_surface_normals"].GetBool():
186
+ self.model_part_controller.ComputeUnitSurfaceNormals()
187
+
188
+ # Process objective gradients
189
+ obj = self.objectives[0]
190
+ obj_id = obj["identifier"].GetString()
191
+
192
+ obj_gradients_dict = self.communicator.getStandardizedGradient(obj_id)
193
+
194
+ nodal_variable = KM.KratosGlobals.GetVariable("DF1DX")
195
+ WriteDictionaryDataOnNodalVariable(obj_gradients_dict, self.optimization_model_part, nodal_variable)
196
+
197
+ # Projection on surface normals
198
+ if obj["project_gradient_on_surface_normals"].GetBool():
199
+ self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(nodal_variable)
200
+
201
+ # Damping
202
+ self.model_part_controller.DampNodalSensitivityVariableIfSpecified(nodal_variable)
203
+
204
+ # Mapping
205
+ nodal_variable_mapped = KM.KratosGlobals.GetVariable("DF1DX_MAPPED")
206
+ self.mapper.Update()
207
+ self.mapper.InverseMap(nodal_variable, nodal_variable_mapped)
208
+ self.mapper.Map(nodal_variable_mapped, nodal_variable_mapped)
209
+
210
+ # Damping
211
+ self.model_part_controller.DampNodalUpdateVariableIfSpecified(nodal_variable_mapped)
212
+
213
+ # Process constraint gradients
214
+ for itr in range(self.constraints.size()):
215
+ con = self.constraints[itr]
216
+ con_id = con["identifier"].GetString()
217
+
218
+ eq_gradients_dict = self.communicator.getStandardizedGradient(con_id)
219
+
220
+ nodal_variable = KM.KratosGlobals.GetVariable("DC"+str(itr+1)+"DX")
221
+ WriteDictionaryDataOnNodalVariable(eq_gradients_dict, self.optimization_model_part, nodal_variable)
222
+
223
+ # Projection on surface normals
224
+ if con["project_gradient_on_surface_normals"].GetBool():
225
+ self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(nodal_variable)
226
+
227
+ # Damping
228
+ self.model_part_controller.DampNodalSensitivityVariableIfSpecified(nodal_variable)
229
+
230
+ # Mapping
231
+ nodal_variable_mapped = KM.KratosGlobals.GetVariable(f"DC{(itr+1)}DX_MAPPED")
232
+ self.mapper.InverseMap(nodal_variable, nodal_variable_mapped)
233
+ self.mapper.Map(nodal_variable_mapped, nodal_variable_mapped)
234
+
235
+ # Damping
236
+ self.model_part_controller.DampNodalUpdateVariableIfSpecified(nodal_variable_mapped)
237
+
238
+ # --------------------------------------------------------------------------
239
+ def __ConvertAnalysisResultsToLengthDirectionFormat(self):
240
+ # Convert objective results
241
+ obj = self.objectives[0]
242
+ obj_id = obj["identifier"].GetString()
243
+
244
+ nodal_variable = KM.KratosGlobals.GetVariable("DF1DX")
245
+ nodal_variable_mapped = KM.KratosGlobals.GetVariable("DF1DX_MAPPED")
246
+
247
+ obj_value = self.communicator.getStandardizedValue(obj_id)
248
+ obj_gradient = ReadNodalVariableToList(self.design_surface, nodal_variable)
249
+ obj_gradient_mapped = ReadNodalVariableToList(self.design_surface, nodal_variable_mapped)
250
+
251
+ dir_obj, len_obj = self.__ConvertToLengthDirectionFormat(obj_value, obj_gradient, obj_gradient_mapped)
252
+ dir_obj = dir_obj
253
+
254
+ # Convert constraints
255
+ len_eqs = []
256
+ dir_eqs = []
257
+ len_ineqs = []
258
+ dir_ineqs = []
259
+
260
+ for itr in range(self.constraints.size()):
261
+ con = self.constraints[itr]
262
+ con_id = con["identifier"].GetString()
263
+
264
+ nodal_variable = KM.KratosGlobals.GetVariable(f"DC{(itr+1)}DX")
265
+ nodal_variable_mapped = KM.KratosGlobals.GetVariable(f"DC{(itr+1)}DX_MAPPED")
266
+
267
+ value = self.communicator.getStandardizedValue(con_id)
268
+ gradient = ReadNodalVariableToList(self.design_surface, nodal_variable)
269
+ gradient_mapped = ReadNodalVariableToList(self.design_surface, nodal_variable_mapped)
270
+
271
+ direction, length = self.__ConvertToLengthDirectionFormat(value, gradient, gradient_mapped)
272
+
273
+ if con["type"].GetString()=="=":
274
+ dir_eqs.append(direction)
275
+ len_eqs.append(length)
276
+ else:
277
+ dir_ineqs.append(direction)
278
+ len_ineqs.append(length)
279
+
280
+ return len_obj, dir_obj, len_eqs, dir_eqs, len_ineqs, dir_ineqs
281
+
282
+ # --------------------------------------------------------------------------
283
+ @staticmethod
284
+ def __ConvertToLengthDirectionFormat(value, gradient, modified_gradient):
285
+ norm_inf = cm.NormInf3D(modified_gradient)
286
+ if norm_inf > 1e-12:
287
+ direction = cm.ScalarVectorProduct(-1/norm_inf,modified_gradient)
288
+ length = -value/cm.Dot(gradient, direction)
289
+ else:
290
+ KM.Logger.PrintWarning("ShapeOpt::AlgorithmTrustRegion", "Vanishing norm-infinity for gradient detected!")
291
+ direction = modified_gradient
292
+ length = 0.0
293
+
294
+ return direction, length
295
+
296
+ # --------------------------------------------------------------------------
297
+ def __DetermineMaxStepLength(self):
298
+ if self.opt_iteration < 4:
299
+ return self.algorithm_settings["max_step_length"].GetDouble()
300
+ else:
301
+ obj_id = self.objectives[0]["identifier"].GetString()
302
+ current_obj_val = self.communicator.getStandardizedValue(obj_id)
303
+ obj_history = self.data_logger.GetValues("response_value")[obj_id]
304
+ step_history = self.data_logger.GetValues("step_length")
305
+
306
+ # Check for osciallation
307
+ objective_is_oscillating = False
308
+ is_decrease_1 = (current_obj_val - obj_history[self.opt_iteration-1])< 0
309
+ is_decrease_2 = (obj_history[self.opt_iteration-1] - obj_history[self.opt_iteration-2])<0
310
+ is_decrease_3 = (current_obj_val - obj_history[self.opt_iteration-3])< 0
311
+ if (is_decrease_1 and is_decrease_2== False and is_decrease_3) or (is_decrease_1== False and is_decrease_2 and is_decrease_3==False):
312
+ objective_is_oscillating = True
313
+
314
+ # Reduce step length if certain conditions are fullfilled
315
+ if objective_is_oscillating:
316
+ return step_history[self.opt_iteration-1]*self.algorithm_settings["step_length_reduction_factor"].GetDouble()
317
+ else:
318
+ return step_history[self.opt_iteration-1]
319
+
320
+ # --------------------------------------------------------------------------
321
+ @staticmethod
322
+ def __ExpressInStepLengthUnit(len_obj, len_eqs, len_ineqs, step_length):
323
+ len_bar_obj = 1/step_length * len_obj
324
+ len_bar_eqs = cm.ScalarVectorProduct(1/step_length, len_eqs)
325
+ len_bar_ineqs = cm.ScalarVectorProduct(1/step_length, len_ineqs)
326
+ return len_bar_obj, len_bar_eqs, len_bar_ineqs
327
+
328
+ # --------------------------------------------------------------------------
329
+ def __DetermineStep(self, len_obj, dir_obj, len_eqs, dir_eqs, len_ineqs, dir_ineqs):
330
+ KM.Logger.Print("")
331
+ KM.Logger.PrintInfo("ShapeOpt", "Starting determination of step...")
332
+
333
+ timer = Timer()
334
+ timer.StartTimer()
335
+
336
+ # Create projector object wich can do the projection in the orthogonalized subspace
337
+ projector = Projector(len_obj, dir_obj, len_eqs, dir_eqs, len_ineqs, dir_ineqs, self.algorithm_settings)
338
+
339
+ # 1. Test projection if there is room for objective improvement
340
+ # I.e., the actual step length to become feasible for an inactive threshold is smaller than 1 and hence a part of the step can be dedicated to objective improvement
341
+ len_obj_test = 0.01
342
+ inactive_threshold = 100
343
+ test_norm_dX, is_projection_sucessfull = projector.RunProjection(len_obj_test, inactive_threshold)
344
+
345
+ KM.Logger.PrintInfo("ShapeOpt", "Time needed for one projection step = ", timer.GetTotalTime(), "s")
346
+
347
+ # 2. Determine step following two different modes depending on the previos found step length to the feasible domain
348
+ if is_projection_sucessfull:
349
+ if test_norm_dX < 1: # Minimizing mode
350
+ KM.Logger.Print("")
351
+ KM.Logger.PrintInfo("ShapeOpt", "Computing projection case 1...")
352
+
353
+ func = lambda len_obj: projector.RunProjection(len_obj, inactive_threshold)
354
+
355
+ len_obj_min = len_obj_test
356
+ len_obj_max = 1.3
357
+ bi_target = 1
358
+ bi_tolerance = self.algorithm_settings["bisectioning_tolerance"].GetDouble()
359
+ bi_max_itr = self.algorithm_settings["bisectioning_max_itr"].GetInt()
360
+ len_obj_result, bi_itrs, bi_err = cm.PerformBisectioning(func, len_obj_min, len_obj_max, bi_target, bi_tolerance, bi_max_itr)
361
+
362
+ projection_results = projector.GetDetailedResultsOfLatestProjection()
363
+
364
+ else: # Correction mode
365
+ KM.Logger.Print("")
366
+ KM.Logger.PrintInfo("ShapeOpt", "Computing projection case 2...")
367
+
368
+ len_obj = self.algorithm_settings["obj_share_during_correction"].GetDouble()
369
+ func = lambda threshold: projector.RunProjection(len_obj, threshold)
370
+
371
+ threshold_min = 0
372
+ threshold_max = 1.3
373
+ bi_target = 1
374
+ bi_tolerance = self.algorithm_settings["bisectioning_tolerance"].GetDouble()
375
+ bi_max_itr = self.algorithm_settings["bisectioning_max_itr"].GetInt()
376
+ l_threshold_result, bi_itrs, bi_err = cm.PerformBisectioning(func, threshold_min, threshold_max, bi_target, bi_tolerance, bi_max_itr)
377
+
378
+ projection_results = projector.GetDetailedResultsOfLatestProjection()
379
+ else:
380
+ raise RuntimeError("Case of not converged test projection not yet implemented yet!")
381
+
382
+ KM.Logger.Print("")
383
+ KM.Logger.PrintInfo("ShapeOpt", "Time needed for determining step = ", timer.GetTotalTime(), "s")
384
+
385
+ process_details = { "test_norm_dX": test_norm_dX,
386
+ "bi_itrs":bi_itrs,
387
+ "bi_err":bi_err,
388
+ "adj_len_obj": projection_results["adj_len_obj"],
389
+ "adj_len_eqs": projection_results["adj_len_eqs"],
390
+ "adj_len_ineqs": projection_results["adj_len_ineqs"] }
391
+
392
+ return projection_results["dX"], process_details
393
+
394
+ # --------------------------------------------------------------------------
395
+ def __ComputeShapeUpdate(self, dX_bar, step_length):
396
+ # Compute update in regular units
397
+ dX = cm.ScalarVectorProduct(step_length,dX_bar)
398
+
399
+ WriteListToNodalVariable(dX, self.design_surface, KSO.SHAPE_UPDATE)
400
+ self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.SHAPE_UPDATE, KSO.SHAPE_CHANGE)
401
+
402
+ return dX
403
+
404
+ # --------------------------------------------------------------------------
405
+ def __LogCurrentOptimizationStep(self, additional_values_to_log):
406
+ self.data_logger.LogSensitivityHeatmap(self.opt_iteration, self.mapper)
407
+ self.data_logger.LogCurrentValues(self.opt_iteration, additional_values_to_log)
408
+ self.data_logger.LogCurrentDesign(self.opt_iteration)
409
+
410
+ # --------------------------------------------------------------------------
411
+ def __CombineConstraintDataToOrderedList(self, eqs_data_list, ineqs_data_list):
412
+ num_eqs = 0
413
+ num_ineqs = 0
414
+ combined_list = []
415
+
416
+ # Order is given by appearance of constraints in optimization settings
417
+ for itr in range(self.constraints.size()):
418
+ if self.constraints[itr]["type"].GetString()=="=":
419
+ combined_list.append(eqs_data_list[num_eqs])
420
+ num_eqs = num_eqs+1
421
+ else:
422
+ combined_list.append(ineqs_data_list[num_ineqs])
423
+ num_ineqs = num_ineqs+1
424
+
425
+ return combined_list
426
+
427
+ # ==============================================================================
428
+ class Projector():
429
+ # --------------------------------------------------------------------------
430
+ def __init__(self, len_obj, dir_obj, len_eqs, dir_eqs, len_ineqs, dir_ineqs, settings):
431
+
432
+ # Store settings
433
+ self.far_away_length = settings["far_away_length"].GetDouble()
434
+ self.subopt_max_itr = settings["subopt_max_itr"].GetInt()
435
+ self.subopt_tolerance = settings["subopt_tolerance"].GetDouble()
436
+
437
+ # Initialize projection results
438
+ self.are_projection_restuls_stored = False
439
+ self.projection_results = {}
440
+
441
+ # Reduce input data to relevant info
442
+ self.input_len_obj = len_obj
443
+ self.input_len_eqs = len_eqs
444
+ self.input_len_ineqs = len_ineqs
445
+
446
+ len_eqs, dir_eqs, remaining_eqs_entries = self.__ReduceToRelevantEqualityConstraints(len_eqs, dir_eqs)
447
+ len_ineqs, dir_ineqs, remaining_ineqs_entries = self.__ReduceToRelevantInequalityConstraints(len_ineqs, dir_ineqs)
448
+
449
+ # Store some working variables depening on data reduction
450
+ self.remaining_eqs_entries = remaining_eqs_entries
451
+ self.remaining_ineqs_entries = remaining_ineqs_entries
452
+ self.len_eqs = len_eqs
453
+ self.len_ineqs = len_ineqs
454
+ self.num_eqs = len(len_eqs)
455
+ self.num_ineqs = len(len_ineqs)
456
+ self.num_unknowns = 1 + self.num_eqs + self.num_ineqs
457
+
458
+ # Create orthogonal basis
459
+ vector_space = [dir_obj]
460
+ for itr in range(len(dir_eqs)):
461
+ vector_space = cm.HorzCat(vector_space, dir_eqs[itr])
462
+ for itr in range(len(dir_ineqs)):
463
+ vector_space = cm.HorzCat(vector_space, dir_ineqs[itr])
464
+ self.ortho_basis = cm.PerformGramSchmidtOrthogonalization(vector_space)
465
+
466
+ # Transform directions to orthogonal space since they don't change with different projections
467
+ self.dir_obj_o = cm.TranslateToNewBasis(dir_obj, self.ortho_basis)
468
+ self.dir_eqs_o = cm.TranslateToNewBasis(dir_eqs, self.ortho_basis)
469
+ self.dir_ineqs_o = cm.TranslateToNewBasis(dir_ineqs, self.ortho_basis)
470
+
471
+ # Make sure directions of constraints are stored as matrix
472
+ self.dir_eqs_o = cm.SafeConvertVectorToMatrix(self.dir_eqs_o)
473
+ self.dir_ineqs_o = cm.SafeConvertVectorToMatrix(self.dir_ineqs_o)
474
+
475
+ # --------------------------------------------------------------------------
476
+ def RunProjection(self, len_obj, threshold):
477
+
478
+ # Adjust halfspaces according input
479
+ adj_len_obj, adj_len_eqs, adj_len_ineqs = self.__AdjustHalfSpacesAndHyperplanes(len_obj, threshold)
480
+
481
+ # Determine position of border of halfspaces and hyperplanes
482
+ pos_obj_o, pos_eqs_o, pos_ineqs_o = self.__DetermineConstraintBorders(adj_len_obj, adj_len_eqs, adj_len_ineqs)
483
+
484
+ # Project current position onto intersection of
485
+ current_position = cm.ZeroVector(self.num_unknowns)
486
+ dlambda_hp = self.__ProjectToHyperplanes(current_position, self.dir_eqs_o, pos_eqs_o)
487
+
488
+ # Project position and direction of halfspaces onto intersection of hyperplanes
489
+ zero_position_eqs_o = cm.ZeroMatrix(self.num_unknowns,self.num_eqs)
490
+
491
+ pos_obj_hp = self.__ProjectToHyperplanes(pos_obj_o, cm.HorzCat(self.dir_eqs_o, self.dir_obj_o), cm.HorzCat(pos_eqs_o, pos_obj_o))
492
+ dir_obj_hp = self.__ProjectToHyperplanes(self.dir_obj_o, self.dir_eqs_o, zero_position_eqs_o)
493
+
494
+ pos_ineqs_hp = []
495
+ dir_ineqs_hp = []
496
+ for itr in range(self.num_ineqs):
497
+ pos_ineqs_hp_i = self.__ProjectToHyperplanes(pos_ineqs_o[itr], cm.HorzCat(self.dir_eqs_o, self.dir_ineqs_o[itr]), cm.HorzCat(pos_eqs_o, pos_ineqs_o[itr]))
498
+ dir_ineqs_hp_i = self.__ProjectToHyperplanes(self.dir_ineqs_o[itr], self.dir_eqs_o, zero_position_eqs_o)
499
+
500
+ pos_ineqs_hp.append(pos_ineqs_hp_i)
501
+ dir_ineqs_hp.append(dir_ineqs_hp_i)
502
+
503
+ # Project onto adjusted halfspaces along the intersection of hyperplanes
504
+ dX_o, _, _, exit_code = self.__ProjectToHalfSpaces(dlambda_hp, cm.HorzCat(pos_ineqs_hp, pos_obj_hp), cm.HorzCat(dir_ineqs_hp, dir_obj_hp))
505
+
506
+ # Determine return values
507
+ if exit_code == 0:
508
+ is_projection_sucessfull = True
509
+
510
+ # Backtransformation and multiplication with -1 because the direction vectors are chosen opposite to the gradients such that the lengths are positive if violated
511
+ dX = cm.ScalarVectorProduct(-1, cm.TranslateToOriginalBasis(dX_o, self.ortho_basis))
512
+ norm_dX = cm.NormInf3D(dX)
513
+ else:
514
+ is_projection_sucessfull = False
515
+
516
+ dX = []
517
+ norm_dX = 1e10
518
+
519
+ self.__StoreProjectionResults(norm_dX, dX, is_projection_sucessfull, adj_len_obj, adj_len_eqs, adj_len_ineqs)
520
+
521
+ return norm_dX, is_projection_sucessfull
522
+
523
+
524
+ # --------------------------------------------------------------------------
525
+ def GetDetailedResultsOfLatestProjection(self):
526
+ if self.are_projection_restuls_stored == False:
527
+ raise RuntimeError("Projector::__StoreProjectionResults: No projection results stored yet!")
528
+
529
+ return self.projection_results
530
+
531
+ # --------------------------------------------------------------------------
532
+ @staticmethod
533
+ def __ReduceToRelevantEqualityConstraints(len_eqs, dir_eqs):
534
+ len_eqs_relevant = []
535
+ dir_eqs_relevant = []
536
+ remaining_entries = []
537
+
538
+ for itr in range(len(dir_eqs)):
539
+ len_i = len_eqs[itr]
540
+ dir_i = dir_eqs[itr]
541
+
542
+ is_no_gradient_info_available = cm.NormInf3D(dir_i) < 1e-13
543
+
544
+ if is_no_gradient_info_available:
545
+ pass
546
+ else:
547
+ remaining_entries.append(itr)
548
+ len_eqs_relevant.append(len_i)
549
+ dir_eqs_relevant.append(dir_i)
550
+
551
+ return len_eqs_relevant, dir_eqs_relevant, remaining_entries
552
+
553
+ # --------------------------------------------------------------------------
554
+ def __ReduceToRelevantInequalityConstraints(self, len_ineqs, dir_ineqs):
555
+ len_ineqs_relevant = []
556
+ dir_ineqs_relevant = []
557
+ remaining_entries = []
558
+
559
+ for itr in range(len(dir_ineqs)):
560
+ len_i = len_ineqs[itr]
561
+ dir_i = dir_ineqs[itr]
562
+
563
+ is_no_gradient_info_available = cm.NormInf3D(dir_i) < 1e-13
564
+ is_constraint_inactive_and_far_away = len_i < -self.far_away_length
565
+
566
+ if is_no_gradient_info_available or is_constraint_inactive_and_far_away:
567
+ pass
568
+ else:
569
+ remaining_entries.append(itr)
570
+ len_ineqs_relevant.append(len_i)
571
+ dir_ineqs_relevant.append(dir_i)
572
+
573
+ return len_ineqs_relevant, dir_ineqs_relevant, remaining_entries
574
+
575
+ # --------------------------------------------------------------------------
576
+ def __AdjustHalfSpacesAndHyperplanes(self, len_obj, threshold):
577
+ if threshold<len_obj:
578
+ len_obj = threshold
579
+
580
+ len_eqs = copy.deepcopy(self.len_eqs)
581
+ len_ineqs = copy.deepcopy(self.len_ineqs)
582
+
583
+ for itr in range(self.num_eqs):
584
+ len_eqs[itr] = min(max(self.len_eqs[itr],-threshold),threshold)
585
+
586
+ for itr in range(self.num_ineqs):
587
+ len_ineqs[itr] = min(self.len_ineqs[itr],threshold)
588
+
589
+ return len_obj, len_eqs, len_ineqs
590
+
591
+ # --------------------------------------------------------------------------
592
+ def __DetermineConstraintBorders(self, len_obj, len_eqs, len_ineqs):
593
+ pos_obj = cm.ScalarVectorProduct(-len_obj,self.dir_obj_o)
594
+
595
+ pos_eqs = []
596
+ pos_ineqs = []
597
+ for i in range(self.num_eqs):
598
+ pos_eqs.append(cm.ScalarVectorProduct(-len_eqs[i],self.dir_eqs_o[i]))
599
+
600
+ for i in range(self.num_ineqs):
601
+ pos_ineqs.append(cm.ScalarVectorProduct(-len_ineqs[i],self.dir_ineqs_o[i]))
602
+
603
+ return pos_obj, pos_eqs, pos_ineqs
604
+
605
+ # --------------------------------------------------------------------------
606
+ @staticmethod
607
+ def __ProjectToHyperplanes(vector, dir_hps, pos_hps):
608
+ if cm.IsEmpty(dir_hps):
609
+ return vector
610
+
611
+ num_hps = len(dir_hps)
612
+
613
+ tmp_mat = cm.Prod(cm.Trans(dir_hps),dir_hps)
614
+ tmp_vec = [ cm.Dot(dir_hps[j],cm.Minus(pos_hps[j],vector)) for j in range(num_hps) ]
615
+
616
+ tmp_solution = cm.SolveLinearSystem(tmp_mat,tmp_vec)
617
+
618
+ return cm.Plus(cm.Prod(dir_hps,tmp_solution),vector)
619
+
620
+ # --------------------------------------------------------------------------
621
+ def __ProjectToHalfSpaces(self, dX0, pos_hss, dir_hss):
622
+ A = cm.Trans(dir_hss)
623
+ b = [ cm.Dot(pos_hss[i],dir_hss[i]) for i in range(cm.RowSize(A)) ]
624
+
625
+ dX_o, subopt_itr, error, exit_code = cm.QuadProg(A, b, self.subopt_max_itr, self.subopt_tolerance)
626
+
627
+ # Consider initial delta
628
+ dX_o = cm.Plus(dX_o,dX0)
629
+
630
+ return dX_o, subopt_itr, error, exit_code
631
+
632
+ # --------------------------------------------------------------------------
633
+ def __StoreProjectionResults(self, norm_dX, dX, is_projection_sucessfull, adj_len_obj, adj_len_eqs, adj_len_ineqs):
634
+ self.are_projection_restuls_stored = True
635
+ self.projection_results["norm_dX"] = norm_dX
636
+ self.projection_results["dX"] = dX
637
+ self.projection_results["is_projection_sucessfull"] = is_projection_sucessfull
638
+ self.projection_results["adj_len_obj"] = adj_len_obj
639
+ self.projection_results["adj_len_eqs"], self.projection_results["adj_len_ineqs"] = self.__CompleteConstraintLengthsWithRemovedEntries(adj_len_eqs, adj_len_ineqs)
640
+
641
+ # --------------------------------------------------------------------------
642
+ def __CompleteConstraintLengthsWithRemovedEntries(self, len_eqs, len_ineqs):
643
+ # Complete list of eqs
644
+ complete_list_eqs = copy.deepcopy(self.input_len_eqs)
645
+ for itr in range(len(len_eqs)):
646
+ original_eq_number = self.remaining_eqs_entries[itr]
647
+ complete_list_eqs[original_eq_number] = len_eqs[itr]
648
+
649
+ # Complete list of ineqs
650
+ complete_list_ineqs = copy.deepcopy(self.input_len_ineqs)
651
+ for itr in range(len(len_ineqs)):
652
+ original_eq_number = self.remaining_ineqs_entries[itr]
653
+ complete_list_ineqs[original_eq_number] = len_ineqs[itr]
654
+
655
+ return complete_list_eqs, complete_list_ineqs
656
+
657
+ # ==============================================================================