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,622 @@
1
+ # ==============================================================================
2
+ # KratosShapeOptimizationApplication
3
+ #
4
+ # License: BSD License
5
+ # license: ShapeOptimizationApplication/license.txt
6
+ #
7
+ # Main authors: Schmölz David, https://github.com/dschmoelz
8
+ #
9
+ # ==============================================================================
10
+
11
+ # Making KratosMultiphysics backward compatible with python 2.6 and 2.7
12
+ from __future__ import print_function, absolute_import, division
13
+
14
+ # Kratos Core and Apps
15
+ import KratosMultiphysics as Kratos
16
+ import KratosMultiphysics.ShapeOptimizationApplication as KSO
17
+ from KratosMultiphysics.LinearSolversApplication import dense_linear_solver_factory
18
+
19
+ # Additional imports
20
+ from KratosMultiphysics.ShapeOptimizationApplication.utilities import custom_math as cm
21
+ from KratosMultiphysics.ShapeOptimizationApplication.algorithms.algorithm_base import OptimizationAlgorithm
22
+ from KratosMultiphysics.ShapeOptimizationApplication import mapper_factory
23
+ from KratosMultiphysics.ShapeOptimizationApplication.loggers import data_logger_factory
24
+ from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_timer import Timer
25
+ from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_variable_utilities import WriteDictionaryDataOnNodalVariable, ReadNodalVariableToList
26
+
27
+ import math
28
+ import time as timer
29
+
30
+ # ==============================================================================
31
+ class AlgorithmShapeFractionOptimization(OptimizationAlgorithm):
32
+ # --------------------------------------------------------------------------
33
+ def __init__(self, optimization_settings, analyzer, communicator, model_part_controller):
34
+ default_algorithm_settings = Kratos.Parameters("""
35
+ {
36
+ "name" : "shape_fraction_optimization",
37
+ "max_correction_share" : 0.75,
38
+ "max_iterations" : 100,
39
+ "relative_tolerance" : 1e-3,
40
+ "shape_fraction" : {
41
+ "penalty_method" : "exterior",
42
+ "max_fraction" : 0.5,
43
+ "nodal_tolerance" : 0.1,
44
+ "inner_tolerance" : 0.01,
45
+ "max_inner_steps" : 10,
46
+ "initial_penalty_factor": 0.1,
47
+ "penalty_scale_factor": 1.25
48
+ },
49
+ "line_search" : {
50
+ "line_search_type" : "manual_stepping",
51
+ "normalize_search_direction" : true,
52
+ "step_size" : 1.0
53
+ }
54
+ }""")
55
+ self.algorithm_settings = optimization_settings["optimization_algorithm"]
56
+ self.algorithm_settings.RecursivelyValidateAndAssignDefaults(default_algorithm_settings)
57
+
58
+ self.optimization_settings = optimization_settings
59
+ self.mapper_settings = optimization_settings["design_variables"]["filter"]
60
+
61
+ self.analyzer = analyzer
62
+ self.communicator = communicator
63
+ self.model_part_controller = model_part_controller
64
+
65
+ self.design_surface = None
66
+ self.mapper = None
67
+ self.data_logger = None
68
+ self.optimization_utilities = None
69
+
70
+ self.objectives = optimization_settings["objectives"]
71
+ self.constraints = optimization_settings["constraints"]
72
+ self.constraint_gradient_variables = {}
73
+ for itr, constraint in enumerate(self.constraints.values()):
74
+ self.constraint_gradient_variables.update({
75
+ constraint["identifier"].GetString() : {
76
+ "gradient": Kratos.KratosGlobals.GetVariable("DC"+str(itr+1)+"DX"),
77
+ "mapped_gradient": Kratos.KratosGlobals.GetVariable("DC"+str(itr+1)+"DX_MAPPED")
78
+ }
79
+ })
80
+ self.max_correction_share = self.algorithm_settings["max_correction_share"].GetDouble()
81
+
82
+ self.step_size = self.algorithm_settings["line_search"]["step_size"].GetDouble()
83
+ self.max_iterations = self.algorithm_settings["max_iterations"].GetInt() + 1
84
+ self.relative_tolerance = self.algorithm_settings["relative_tolerance"].GetDouble()
85
+
86
+ self.optimization_model_part = model_part_controller.GetOptimizationModelPart()
87
+ self.optimization_model_part.AddNodalSolutionStepVariable(KSO.SEARCH_DIRECTION)
88
+ self.optimization_model_part.AddNodalSolutionStepVariable(KSO.CORRECTION)
89
+ self.optimization_model_part.AddNodalSolutionStepVariable(KSO.DP1DX)
90
+ self.optimization_model_part.AddNodalSolutionStepVariable(KSO.DPF1DX)
91
+
92
+ # shape fraction related settings
93
+ self.penalty_method = self.algorithm_settings["shape_fraction"]["penalty_method"].GetString()
94
+ self.max_shape_fraction = self.algorithm_settings["shape_fraction"]["max_fraction"].GetDouble()
95
+ self.frac_tolerance = self.algorithm_settings["shape_fraction"]["nodal_tolerance"].GetDouble()
96
+ self.inner_tolerance = self.algorithm_settings["shape_fraction"]["inner_tolerance"].GetDouble()
97
+ self.max_inner_steps = self.algorithm_settings["shape_fraction"]["max_inner_steps"].GetDouble()
98
+ self.initial_penalty_factor = self.algorithm_settings["shape_fraction"]["initial_penalty_factor"].GetDouble()
99
+ self.gamma = self.algorithm_settings["shape_fraction"]["penalty_scale_factor"].GetDouble()
100
+ if self.gamma <= 1.0:
101
+ raise RuntimeError("Shape fraction algorithm: 'penalty_scale_factor' has to be larger than 1.0!")
102
+ self.inner_step = 0
103
+ self.penalty_factor = 0.0
104
+ self.epsilon = -0.2
105
+ self.previous_objective_value = None
106
+
107
+ # --------------------------------------------------------------------------
108
+ def CheckApplicability(self):
109
+ if self.objectives.size() > 1:
110
+ raise RuntimeError("Shape fraction algorithm only supports one objective function!")
111
+
112
+ # --------------------------------------------------------------------------
113
+ def InitializeOptimizationLoop(self):
114
+ self.model_part_controller.Initialize()
115
+
116
+ self.analyzer.InitializeBeforeOptimizationLoop()
117
+
118
+ self.design_surface = self.model_part_controller.GetDesignSurface()
119
+
120
+ self.mapper = mapper_factory.CreateMapper(self.design_surface, self.design_surface, self.mapper_settings)
121
+ self.mapper.Initialize()
122
+ self.model_part_controller.InitializeDamping()
123
+
124
+ self.data_logger = data_logger_factory.CreateDataLogger(self.model_part_controller, self.communicator, self.optimization_settings)
125
+ self.data_logger.InitializeDataLogging()
126
+
127
+ self.optimization_utilities = KSO.OptimizationUtilities
128
+
129
+ # --------------------------------------------------------------------------
130
+ def RunOptimizationLoop(self):
131
+ timer = Timer()
132
+ timer.StartTimer()
133
+
134
+ for self.optimization_iteration in range(1,self.max_iterations):
135
+ Kratos.Logger.Print("")
136
+ Kratos.Logger.Print("===============================================================================")
137
+ Kratos.Logger.PrintInfo("ShapeOpt", timer.GetTimeStamp(), ": Starting optimization iteration ", self.optimization_iteration)
138
+ Kratos.Logger.Print("===============================================================================\n")
139
+
140
+ timer.StartNewLap()
141
+
142
+ self.__initializeNewShape()
143
+
144
+ self.__analyzeShape()
145
+
146
+ self.__computeShapeUpdate()
147
+
148
+ self.__logCurrentOptimizationStep()
149
+
150
+ Kratos.Logger.Print("")
151
+ Kratos.Logger.PrintInfo("ShapeOpt", "Time needed for current optimization step = ", timer.GetLapTime(), "s")
152
+ Kratos.Logger.PrintInfo("ShapeOpt", "Time needed for total optimization so far = ", timer.GetTotalTime(), "s")
153
+
154
+ if self.__isAlgorithmConverged():
155
+ break
156
+ else:
157
+ self.__determineAbsoluteChanges()
158
+
159
+ # --------------------------------------------------------------------------
160
+ def FinalizeOptimizationLoop(self):
161
+ self.data_logger.FinalizeDataLogging()
162
+ self.analyzer.FinalizeAfterOptimizationLoop()
163
+
164
+ # --------------------------------------------------------------------------
165
+ def __initializeNewShape(self):
166
+ self.model_part_controller.UpdateTimeStep(self.optimization_iteration)
167
+ self.model_part_controller.UpdateMeshAccordingInputVariable(KSO.SHAPE_UPDATE)
168
+ self.model_part_controller.SetReferenceMeshToMesh()
169
+
170
+ # --------------------------------------------------------------------------
171
+ def __analyzeShape(self):
172
+ self.communicator.initializeCommunication()
173
+ self.communicator.requestValueOf(self.objectives[0]["identifier"].GetString())
174
+ self.communicator.requestGradientOf(self.objectives[0]["identifier"].GetString())
175
+
176
+ for constraint in self.constraints.values():
177
+ con_id = constraint["identifier"].GetString()
178
+ self.communicator.requestValueOf(con_id)
179
+ self.communicator.requestGradientOf(con_id)
180
+
181
+ self.analyzer.AnalyzeDesignAndReportToCommunicator(self.optimization_model_part, self.optimization_iteration, self.communicator)
182
+
183
+ # compute normals only if required
184
+ surface_normals_required = self.objectives[0]["project_gradient_on_surface_normals"].GetBool()
185
+ for constraint in self.constraints.values():
186
+ if constraint["project_gradient_on_surface_normals"].GetBool():
187
+ surface_normals_required = True
188
+
189
+ if surface_normals_required:
190
+ self.model_part_controller.ComputeUnitSurfaceNormals()
191
+
192
+ # objective value
193
+ objective_value = self.communicator.getStandardizedValue(self.objectives[0]["identifier"].GetString())
194
+
195
+ # objective gradient
196
+ objGradientDict = self.communicator.getStandardizedGradient(self.objectives[0]["identifier"].GetString())
197
+ WriteDictionaryDataOnNodalVariable(objGradientDict, self.optimization_model_part, KSO.DF1DX)
198
+ objective_gradient = Kratos.Vector()
199
+ self.optimization_utilities.AssembleVector(self.optimization_model_part, objective_gradient, KSO.DF1DX)
200
+ objective_gradient_norm = objective_gradient.norm_2()
201
+
202
+ # response value g of penalty method
203
+ response_value = self.__computeResponseValue()
204
+ Kratos.Logger.PrintInfo("ShapeFractionOptimization", f"Shape Fraction value = {response_value}")
205
+ # penalty value
206
+ # exterior: p = max(0, g)**2
207
+ # extended interior: p = -1/g if g =< epsilon (interior penalty)
208
+ # p = - 2*epsilon - g / epsilon**2 if g > epsilon (exterior penalty)
209
+ self.penalty_value = self.__computePenaltyValue(response_value)
210
+
211
+ # set up initial penalty factor
212
+ if self.penalty_factor == 0.0:
213
+ self.__SetUpInitialPenaltyFactor(objective_value, objective_gradient_norm)
214
+ self.__IncrementInnerStep()
215
+
216
+ # pseudo objective value
217
+ pseudo_objective_value = self.__computePseudoObjectiveValue(objective_value)
218
+
219
+ # check inner convergence
220
+ inner_converged = self.__checkInnerConvergence(pseudo_objective_value)
221
+ # update penalty factor if inner loop converged
222
+ if inner_converged:
223
+ Kratos.Logger.PrintInfo("ShapeFractionOptimization", "Updating penalty factor.")
224
+ self.__updatePenaltyFactor()
225
+
226
+ # update pseudo objective value
227
+ self.pseudo_objective_value = self.__computePseudoObjectiveValue(objective_value)
228
+
229
+ # compute penalty gradient
230
+ # exterior: p = 2 * g * dg/dx
231
+ # extended interior: p = -1/g if g =< epsilon (interior penalty)
232
+ # p = - 2*epsilon - g / epsilon**2 if g > epsilon (exterior penalty)
233
+ penalty_gradient = self.__computePenaltyGradient(response_value)
234
+ self.optimization_utilities.AssignVectorToVariable(self.optimization_model_part, penalty_gradient, KSO.DP1DX)
235
+
236
+ # pseudo objective gradient
237
+ pseudo_objective_gradient = objective_gradient + self.penalty_factor * penalty_gradient
238
+ self.optimization_utilities.AssignVectorToVariable(self.optimization_model_part, pseudo_objective_gradient, KSO.DPF1DX)
239
+
240
+ # project and damp objective gradients
241
+ if self.objectives[0]["project_gradient_on_surface_normals"].GetBool():
242
+ self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(KSO.DPF1DX)
243
+
244
+ self.model_part_controller.DampNodalSensitivityVariableIfSpecified(KSO.DPF1DX)
245
+
246
+ # project and damp constraint gradients
247
+ for constraint in self.constraints.values():
248
+ con_id = constraint["identifier"].GetString()
249
+ conGradientDict = self.communicator.getStandardizedGradient(con_id)
250
+ gradient_variable = self.constraint_gradient_variables[con_id]["gradient"]
251
+ WriteDictionaryDataOnNodalVariable(conGradientDict, self.optimization_model_part, gradient_variable)
252
+
253
+ if constraint["project_gradient_on_surface_normals"].GetBool():
254
+ self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(gradient_variable)
255
+
256
+ self.model_part_controller.DampNodalSensitivityVariableIfSpecified(gradient_variable)
257
+
258
+ # --------------------------------------------------------------------------
259
+ def __computePenaltyValue(self, response_value):
260
+
261
+ if self.penalty_method == "extended_interior":
262
+ g = response_value
263
+ if g > self.epsilon:
264
+ penalty_value = - (2*self.epsilon - g) / self.epsilon**2
265
+ else:
266
+ penalty_value = - 1 / g
267
+
268
+ elif self.penalty_method == "exterior":
269
+ penalty_value = response_value
270
+
271
+ return penalty_value
272
+
273
+ # --------------------------------------------------------------------------
274
+ def __computeResponseValue(self):
275
+
276
+ def __calculateNodalValueExterior(self, node, quantile):
277
+ shape_change = node.GetSolutionStepValue(KSO.SHAPE_CHANGE)
278
+ norm = cm.Norm2(shape_change)
279
+
280
+ if norm > quantile:
281
+ return 0.0
282
+
283
+ if norm > self.frac_tolerance:
284
+ return norm
285
+ else:
286
+ return 0.0
287
+
288
+ def __calculateNodalValueExtendedInterior(self, node, quantile):
289
+ shape_change = node.GetSolutionStepValue(KSO.SHAPE_CHANGE)
290
+ norm = cm.Norm2(shape_change)
291
+
292
+ if norm > quantile:
293
+ return 0.0
294
+ else:
295
+ return norm
296
+
297
+ def __calculateIntegralToleranceOfNode(self, node, quantile):
298
+ shape_change = node.GetSolutionStepValue(KSO.SHAPE_CHANGE)
299
+ norm = cm.Norm2(shape_change)
300
+
301
+ if norm > quantile:
302
+ return 0.0
303
+ else:
304
+ return norm
305
+
306
+ Kratos.Logger.PrintInfo("ShapeFractionOptimization", "Starting calculation of penalty response value:")
307
+
308
+ startTime = timer.time()
309
+ total_integral = 0.0
310
+ integral_tol = 0.0
311
+ quantile = self.__getQuantile()
312
+ for node in self.design_surface.Nodes:
313
+
314
+ if self.penalty_method == "exterior":
315
+ g_i = __calculateNodalValueExterior(self, node, quantile)
316
+ elif self.penalty_method == "extended_interior":
317
+ g_i = __calculateNodalValueExtendedInterior(self, node, quantile)
318
+ g_tol_i = __calculateIntegralToleranceOfNode(self, node, quantile)
319
+ integral_tol += g_tol_i
320
+
321
+ total_integral += g_i
322
+
323
+ if self.penalty_method == "extended_interior":
324
+ g = total_integral - integral_tol
325
+
326
+ elif self.penalty_method == "exterior":
327
+ g = total_integral
328
+
329
+ Kratos.Logger.PrintInfo("ShapeFractionOptimization", "Time needed for calculating the penalty response value = ",round(timer.time() - startTime,2),"s")
330
+
331
+ return g
332
+
333
+
334
+ # --------------------------------------------------------------------------
335
+ def __computePenaltyGradient(self, penalty_value):
336
+
337
+ def __calculateNodalGradient(self, node, quantile):
338
+ shape_change = node.GetSolutionStepValue(KSO.SHAPE_CHANGE)
339
+ norm = cm.Norm2(shape_change)
340
+
341
+ if norm > self.frac_tolerance:
342
+ if norm > quantile:
343
+ return [0.0, 0.0, 0.0]
344
+ else:
345
+ return [
346
+ shape_change[0] / norm,
347
+ shape_change[1] / norm,
348
+ shape_change[2] / norm
349
+ ]
350
+ else:
351
+ return [0.0, 0.0, 0.0]
352
+
353
+ Kratos.Logger.PrintInfo("ShapeFractionOptimization", "Starting calculation of penalty gradient:")
354
+
355
+ startTime = timer.time()
356
+ penalty_gradient = Kratos.Vector(3*len(self.design_surface.Nodes))
357
+ quantile = self.__getQuantile()
358
+
359
+ for i, node in enumerate(self.design_surface.Nodes):
360
+ if self.penalty_method == "exterior":
361
+ if penalty_value > 0.0:
362
+ gradient_i = __calculateNodalGradient(self, node, quantile)
363
+ else:
364
+ gradient_i = [0.0, 0.0, 0.0]
365
+
366
+ elif self.penalty_method == "extended_interior":
367
+ gradient_i = __calculateNodalGradient(self, node, quantile)
368
+ if penalty_value > self.epsilon:
369
+ gradient_i[0] /= self.epsilon**2
370
+ gradient_i[1] /= self.epsilon**2
371
+ gradient_i[2] /= self.epsilon**2
372
+ else:
373
+ gradient_i[0] /= penalty_value**2
374
+ gradient_i[1] /= penalty_value**2
375
+ gradient_i[2] /= penalty_value**2
376
+
377
+ penalty_gradient[3*i:3*i+3] = gradient_i
378
+
379
+ Kratos.Logger.PrintInfo("ShapeFractionOptimization", "Time needed for calculating the penalty gradient = ",round(timer.time() - startTime,2),"s")
380
+
381
+ return penalty_gradient
382
+
383
+ def __getQuantile(self):
384
+
385
+ nodal_variable = Kratos.KratosGlobals.GetVariable("SHAPE_CHANGE")
386
+ shape_change = ReadNodalVariableToList(self.design_surface, nodal_variable)
387
+
388
+ shape_change_norm = []
389
+
390
+ for i in range(int(len(shape_change)/3)):
391
+ shape_change_norm.append(cm.Norm2(shape_change[3*i:3*i+3]))
392
+
393
+ shape_change_norm.sort()
394
+
395
+ index = round(len(shape_change_norm)*(1-self.max_shape_fraction))
396
+
397
+ quantile = shape_change_norm[index]
398
+
399
+ Kratos.Logger.PrintInfo(f"ShapeFractionOptimization: Shape change quantile {(1-self.max_shape_fraction)} = {quantile}")
400
+
401
+ return quantile
402
+
403
+ def __computeShapeFraction(self):
404
+
405
+ n_active = 0
406
+ for node in self.design_surface.Nodes:
407
+ shape_change = node.GetSolutionStepValue(KSO.SHAPE_CHANGE)
408
+ norm = cm.Norm2(shape_change)
409
+
410
+ if norm > self.frac_tolerance:
411
+ n_active += 1
412
+
413
+ total_nodes = len(self.design_surface.Nodes)
414
+
415
+ shape_fraction = n_active / total_nodes
416
+
417
+ return shape_fraction
418
+
419
+ def __computePseudoObjectiveValue(self, objective_value):
420
+ if self.penalty_method == "exterior":
421
+ pseudo_objective_value = objective_value + self.penalty_factor * max(0, self.penalty_value)**2
422
+ elif self.penalty_method == "extended_interior":
423
+ pseudo_objective_value = objective_value + self.penalty_factor * self.penalty_value
424
+
425
+ return pseudo_objective_value
426
+
427
+ # --------------------------------------------------------------------------
428
+ def __IncrementInnerStep(self):
429
+ if self.penalty_method == "exterior" and self.penalty_value > 0:
430
+ self.inner_step += 1
431
+ elif self.penalty_method == "extended_interior":
432
+ self.inner_step += 1
433
+
434
+ # --------------------------------------------------------------------------
435
+ def __checkInnerConvergence(self, objective_value):
436
+
437
+ tolerance = self.inner_tolerance
438
+
439
+ is_converged = False
440
+ if self.previous_objective_value is None:
441
+ self.reference_objective_value = objective_value
442
+ self.previous_objective_value = objective_value
443
+ self.relative_change = 0
444
+ elif self.inner_step >= self.max_inner_steps:
445
+ self.previous_objective_value = objective_value
446
+ is_converged = True
447
+ else:
448
+ self.relative_change = (objective_value - self.previous_objective_value) / self.reference_objective_value
449
+ if abs(self.relative_change) < tolerance:
450
+ is_converged = True
451
+
452
+ self.previous_objective_value = objective_value
453
+
454
+ if is_converged:
455
+ self.inner_step = 0
456
+ self.reference_objective_value = objective_value
457
+
458
+ return is_converged
459
+
460
+ # --------------------------------------------------------------------------
461
+ def __SetUpInitialPenaltyFactor(self, objective_value, objective_gradient_norm):
462
+ if self.penalty_method == "exterior":
463
+ # compute penalty gradients for start penalty factor
464
+ penalty_gradient = self.__computePenaltyGradient(self.penalty_value)
465
+ penalty_gradient_norm = penalty_gradient.norm_2()
466
+ if penalty_gradient_norm > 0:
467
+ self.penalty_factor = self.initial_penalty_factor * objective_gradient_norm / penalty_gradient_norm
468
+ elif self.penalty_method == "extended_interior":
469
+ self.penalty_factor = self.initial_penalty_factor * abs(objective_value / self.penalty_value)
470
+ a = 0.5
471
+ self.C = - self.epsilon / (self.penalty_factor**a)
472
+
473
+ # --------------------------------------------------------------------------
474
+ def __updatePenaltyFactor(self):
475
+
476
+ if self.penalty_method == "exterior" and self.penalty_value > 0.0:
477
+ self.penalty_factor *= self.gamma # increase penalty factor by 25%
478
+
479
+ elif self.penalty_method == "extended_interior":
480
+ self.penalty_factor *= self.gamma # increase penalty factor by 25%
481
+ a = 0.5
482
+ self.epsilon = - self.C * (self.penalty_factor**a)
483
+
484
+ Kratos.Logger.PrintInfo("ShapeOpt", f"New penalty factor = {self.penalty_factor}")
485
+
486
+ # --------------------------------------------------------------------------
487
+ def __computeShapeUpdate(self):
488
+ self.mapper.Update()
489
+ self.mapper.InverseMap(KSO.DPF1DX, KSO.DF1DX_MAPPED)
490
+
491
+ for constraint in self.constraints.values():
492
+ con_id = constraint["identifier"].GetString()
493
+ gradient_variable = self.constraint_gradient_variables[con_id]["gradient"]
494
+ mapped_gradient_variable = self.constraint_gradient_variables[con_id]["mapped_gradient"]
495
+ self.mapper.InverseMap(gradient_variable, mapped_gradient_variable)
496
+
497
+ self.__computeControlPointUpdate()
498
+
499
+ self.mapper.Map(KSO.CONTROL_POINT_UPDATE, KSO.SHAPE_UPDATE)
500
+ self.model_part_controller.DampNodalUpdateVariableIfSpecified(KSO.SHAPE_UPDATE)
501
+
502
+ # --------------------------------------------------------------------------
503
+ def __computeControlPointUpdate(self):
504
+ """adapted from https://msulaiman.org/onewebmedia/GradProj_2.pdf"""
505
+ g_a, g_a_variables = self.__getActiveConstraints()
506
+
507
+ Kratos.Logger.PrintInfo("ShapeOpt", "Assemble vector of objective gradient.")
508
+ nabla_f = Kratos.Vector()
509
+ self.optimization_utilities.AssembleVector(self.design_surface, nabla_f, KSO.DF1DX_MAPPED)
510
+
511
+ s = Kratos.Vector()
512
+
513
+ if len(g_a) == 0:
514
+ Kratos.Logger.PrintInfo("ShapeOpt", "No constraints active, use negative objective gradient as search direction.")
515
+ s = nabla_f * (-1.0)
516
+ s *= self.step_size / s.norm_inf()
517
+ self.optimization_utilities.AssignVectorToVariable(self.design_surface, s, KSO.SEARCH_DIRECTION)
518
+ self.optimization_utilities.AssignVectorToVariable(self.design_surface, [0.0]*len(s), KSO.CORRECTION)
519
+ self.optimization_utilities.AssignVectorToVariable(self.design_surface, s, KSO.CONTROL_POINT_UPDATE)
520
+ return
521
+
522
+
523
+ Kratos.Logger.PrintInfo("ShapeOpt", "Assemble matrix of constraint gradient.")
524
+ N = Kratos.Matrix()
525
+ self.optimization_utilities.AssembleMatrix(self.design_surface, N, g_a_variables)
526
+
527
+ settings = Kratos.Parameters('{ "solver_type" : "LinearSolversApplication.dense_col_piv_householder_qr" }')
528
+ solver = dense_linear_solver_factory.ConstructSolver(settings)
529
+
530
+ Kratos.Logger.PrintInfo("ShapeOpt", "Calculate projected search direction and correction.")
531
+ c = Kratos.Vector()
532
+ self.optimization_utilities.CalculateProjectedSearchDirectionAndCorrection(
533
+ nabla_f,
534
+ N,
535
+ g_a,
536
+ solver,
537
+ s,
538
+ c)
539
+
540
+ if c.norm_inf() != 0.0:
541
+ if c.norm_inf() <= self.max_correction_share * self.step_size:
542
+ delta = self.step_size - c.norm_inf()
543
+ s *= delta/s.norm_inf()
544
+ else:
545
+ Kratos.Logger.PrintWarning("ShapeOpt", f"Correction is scaled down from {c.norm_inf()} to {self.max_correction_share * self.step_size}.")
546
+ c *= self.max_correction_share * self.step_size / c.norm_inf()
547
+ s *= (1.0 - self.max_correction_share) * self.step_size / s.norm_inf()
548
+ else:
549
+ s *= self.step_size / s.norm_inf()
550
+
551
+ self.optimization_utilities.AssignVectorToVariable(self.design_surface, s, KSO.SEARCH_DIRECTION)
552
+ self.optimization_utilities.AssignVectorToVariable(self.design_surface, c, KSO.CORRECTION)
553
+ self.optimization_utilities.AssignVectorToVariable(self.design_surface, s+c, KSO.CONTROL_POINT_UPDATE)
554
+
555
+ # --------------------------------------------------------------------------
556
+ def __getActiveConstraints(self):
557
+ active_constraint_values = []
558
+ active_constraint_variables = []
559
+
560
+ for constraint in self.constraints.values():
561
+ if self.__isConstraintActive(constraint):
562
+ identifier = constraint["identifier"].GetString()
563
+ constraint_value = self.communicator.getStandardizedValue(identifier)
564
+ active_constraint_values.append(constraint_value)
565
+ active_constraint_variables.append(
566
+ self.constraint_gradient_variables[identifier]["mapped_gradient"])
567
+
568
+ return active_constraint_values, active_constraint_variables
569
+
570
+ # --------------------------------------------------------------------------
571
+ def __isConstraintActive(self, constraint):
572
+ identifier = constraint["identifier"].GetString()
573
+ constraint_value = self.communicator.getStandardizedValue(identifier)
574
+ if constraint["type"].GetString() == "=" or constraint_value >= 0:
575
+ gradient_norm = self.optimization_utilities.ComputeMaxNormOfNodalVariable(
576
+ self.design_surface, self.constraint_gradient_variables[identifier]["mapped_gradient"]
577
+ )
578
+ if math.isclose(gradient_norm, 0.0, abs_tol=1e-16):
579
+ Kratos.Logger.PrintWarning("ShapeOpt", f"Gradient for constraint {identifier} is 0.0 - will not be considered!")
580
+ return False
581
+ return True
582
+ else:
583
+ return False
584
+
585
+ # --------------------------------------------------------------------------
586
+ def __logCurrentOptimizationStep(self):
587
+ additional_values_to_log = {}
588
+ additional_values_to_log["penalty_value"] = self.penalty_value
589
+ additional_values_to_log["penalty_factor"] = self.penalty_factor
590
+ additional_values_to_log["f_p"] = self.pseudo_objective_value
591
+ additional_values_to_log["df_rel_p"] = self.relative_change
592
+ additional_values_to_log["shape_fraction"] = self.__computeShapeFraction()
593
+ additional_values_to_log["step_size"] = self.step_size
594
+ additional_values_to_log["inf_norm_s"] = self.optimization_utilities.ComputeMaxNormOfNodalVariable(self.design_surface, KSO.SEARCH_DIRECTION)
595
+ additional_values_to_log["inf_norm_c"] = self.optimization_utilities.ComputeMaxNormOfNodalVariable(self.design_surface, KSO.CORRECTION)
596
+ self.data_logger.LogCurrentValues(self.optimization_iteration, additional_values_to_log)
597
+ self.data_logger.LogCurrentDesign(self.optimization_iteration)
598
+
599
+ # --------------------------------------------------------------------------
600
+ def __isAlgorithmConverged(self):
601
+
602
+ if self.optimization_iteration > 1 :
603
+
604
+ # Check if maximum iterations were reached
605
+ if self.optimization_iteration == self.max_iterations:
606
+ Kratos.Logger.Print("")
607
+ Kratos.Logger.PrintInfo("ShapeOpt", "Maximal iterations of optimization problem reached!")
608
+ return True
609
+
610
+ # Check for relative tolerance
611
+ relative_change_of_objective_value = self.data_logger.GetValues("rel_change_objective")[self.optimization_iteration]
612
+ if abs(relative_change_of_objective_value) < self.relative_tolerance:
613
+ Kratos.Logger.Print("")
614
+ Kratos.Logger.PrintInfo("ShapeOpt", "Optimization problem converged within a relative objective tolerance of ",self.relative_tolerance,"%.")
615
+ return True
616
+
617
+ # --------------------------------------------------------------------------
618
+ def __determineAbsoluteChanges(self):
619
+ self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.CONTROL_POINT_UPDATE, KSO.CONTROL_POINT_CHANGE)
620
+ self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.SHAPE_UPDATE, KSO.SHAPE_CHANGE)
621
+
622
+ # ==============================================================================