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.
- KratosMultiphysics/.libs/KratosShapeOptimizationApplication.so +0 -0
- KratosMultiphysics/.libs/libKratosShapeOptimizationCore.dylib +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/TemplateMainKratosShapeOptimization.py +31 -0
- KratosMultiphysics/ShapeOptimizationApplication/__init__.py +19 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_base.py +31 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_bead_optimization.py +412 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_factory.py +62 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_gradient_projection.py +317 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_penalized_projection.py +225 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +580 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_shape_fraction_optimization.py +622 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_steepest_descent.py +255 -0
- KratosMultiphysics/ShapeOptimizationApplication/algorithms/algorithm_trust_region.py +657 -0
- KratosMultiphysics/ShapeOptimizationApplication/analyzers/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_base.py +30 -0
- KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_empty.py +21 -0
- KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_factory.py +310 -0
- KratosMultiphysics/ShapeOptimizationApplication/analyzers/analyzer_internal.py +155 -0
- KratosMultiphysics/ShapeOptimizationApplication/communicator_factory.py +259 -0
- KratosMultiphysics/ShapeOptimizationApplication/custom_ios/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/custom_ios/wrl_io.py +82 -0
- KratosMultiphysics/ShapeOptimizationApplication/custom_ios/wrl_reader.py +119 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/data_logger_factory.py +199 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_base.py +28 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_gid.py +112 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_unv.py +73 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/design_logger_vtk.py +96 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/sensitivity_heatmap_logger.py +91 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_base.py +128 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_bead_optimization.py +79 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_gradient_projection.py +80 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_penalized_projection.py +79 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_relaxed_gradient_projection.py +108 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_shape_fraction_optimization.py +92 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_steepest_descent.py +64 -0
- KratosMultiphysics/ShapeOptimizationApplication/loggers/value_logger_trust_region.py +100 -0
- KratosMultiphysics/ShapeOptimizationApplication/mapper_factory.py +100 -0
- KratosMultiphysics/ShapeOptimizationApplication/mapping/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/mapping/in_plane_vertex_morphing_mapper.py +140 -0
- KratosMultiphysics/ShapeOptimizationApplication/mapping/sliding_vertex_morphing_mapper.py +378 -0
- KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/mesh_controller_base.py +22 -0
- KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/mesh_controller_basic_updating.py +35 -0
- KratosMultiphysics/ShapeOptimizationApplication/mesh_controllers/mesh_controller_with_solver.py +237 -0
- KratosMultiphysics/ShapeOptimizationApplication/model_part_controller_factory.py +197 -0
- KratosMultiphysics/ShapeOptimizationApplication/optimizer_factory.py +235 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/airfoil_2d_responses.py +189 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/face_angle.py +140 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/mesh_based_packaging.py +70 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/packaging_response_base.py +156 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/plane_based_packaging.py +61 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/response_function_factory.py +40 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/surface_normal_shape_change.py +125 -0
- KratosMultiphysics/ShapeOptimizationApplication/response_functions/total_volume.py +56 -0
- KratosMultiphysics/ShapeOptimizationApplication/utilities/__init__.py +0 -0
- KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_math.py +443 -0
- KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_sensitivity_heatmap.py +235 -0
- KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_timer.py +47 -0
- KratosMultiphysics/ShapeOptimizationApplication/utilities/custom_variable_utilities.py +54 -0
- kratosshapeoptimizationapplication-10.4.4.dist-info/METADATA +31 -0
- kratosshapeoptimizationapplication-10.4.4.dist-info/RECORD +69 -0
- kratosshapeoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
- kratosshapeoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
- kratosshapeoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
- kratosshapeoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
- kratosshapeoptimizationapplication.dylibs/libstdc++.6.dylib +0 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# KratosShapeOptimizationApplication
|
|
3
|
+
#
|
|
4
|
+
# License: BSD License
|
|
5
|
+
# license: ShapeOptimizationApplication/license.txt
|
|
6
|
+
#
|
|
7
|
+
# Main authors: Baumgaertner Daniel, https://github.com/dbaumgaertner
|
|
8
|
+
# Geiser Armin, https://github.com/armingeiser
|
|
9
|
+
#
|
|
10
|
+
# ==============================================================================
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Kratos Core and Apps
|
|
14
|
+
import KratosMultiphysics as KM
|
|
15
|
+
import KratosMultiphysics.ShapeOptimizationApplication as KSO
|
|
16
|
+
from KratosMultiphysics.LinearSolversApplication import dense_linear_solver_factory
|
|
17
|
+
|
|
18
|
+
# Additional imports
|
|
19
|
+
from KratosMultiphysics.ShapeOptimizationApplication.algorithms.algorithm_base import OptimizationAlgorithm
|
|
20
|
+
from KratosMultiphysics.ShapeOptimizationApplication import mapper_factory
|
|
21
|
+
from KratosMultiphysics.ShapeOptimizationApplication.loggers import data_logger_factory
|
|
22
|
+
from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_timer import Timer
|
|
23
|
+
from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_variable_utilities import WriteDictionaryDataOnNodalVariable
|
|
24
|
+
|
|
25
|
+
import math
|
|
26
|
+
|
|
27
|
+
# ==============================================================================
|
|
28
|
+
class AlgorithmGradientProjection(OptimizationAlgorithm):
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
def __init__(self, optimization_settings, analyzer, communicator, model_part_controller):
|
|
31
|
+
default_algorithm_settings = KM.Parameters("""
|
|
32
|
+
{
|
|
33
|
+
"name" : "penalized_projection",
|
|
34
|
+
"max_correction_share" : 0.75,
|
|
35
|
+
"max_iterations" : 100,
|
|
36
|
+
"relative_tolerance" : 1e-3,
|
|
37
|
+
"line_search" : {
|
|
38
|
+
"line_search_type" : "manual_stepping",
|
|
39
|
+
"normalize_search_direction" : true,
|
|
40
|
+
"step_size" : 1.0
|
|
41
|
+
}
|
|
42
|
+
}""")
|
|
43
|
+
self.algorithm_settings = optimization_settings["optimization_algorithm"]
|
|
44
|
+
self.algorithm_settings.RecursivelyValidateAndAssignDefaults(default_algorithm_settings)
|
|
45
|
+
|
|
46
|
+
self.optimization_settings = optimization_settings
|
|
47
|
+
self.mapper_settings = optimization_settings["design_variables"]["filter"]
|
|
48
|
+
|
|
49
|
+
self.analyzer = analyzer
|
|
50
|
+
self.communicator = communicator
|
|
51
|
+
self.model_part_controller = model_part_controller
|
|
52
|
+
|
|
53
|
+
self.design_surface = None
|
|
54
|
+
self.mapper = None
|
|
55
|
+
self.data_logger = None
|
|
56
|
+
self.optimization_utilities = None
|
|
57
|
+
|
|
58
|
+
self.objectives = optimization_settings["objectives"]
|
|
59
|
+
self.constraints = optimization_settings["constraints"]
|
|
60
|
+
self.constraint_gradient_variables = {}
|
|
61
|
+
for itr, constraint in enumerate(self.constraints.values()):
|
|
62
|
+
self.constraint_gradient_variables.update({
|
|
63
|
+
constraint["identifier"].GetString() : {
|
|
64
|
+
"gradient": KM.KratosGlobals.GetVariable(f"DC{(itr+1)}DX"),
|
|
65
|
+
"mapped_gradient": KM.KratosGlobals.GetVariable(f"DC{(itr+1)}DX_MAPPED")
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
self.max_correction_share = self.algorithm_settings["max_correction_share"].GetDouble()
|
|
69
|
+
|
|
70
|
+
self.step_size = self.algorithm_settings["line_search"]["step_size"].GetDouble()
|
|
71
|
+
self.max_iterations = self.algorithm_settings["max_iterations"].GetInt() + 1
|
|
72
|
+
self.relative_tolerance = self.algorithm_settings["relative_tolerance"].GetDouble()
|
|
73
|
+
|
|
74
|
+
self.optimization_model_part = model_part_controller.GetOptimizationModelPart()
|
|
75
|
+
self.optimization_model_part.AddNodalSolutionStepVariable(KSO.SEARCH_DIRECTION)
|
|
76
|
+
self.optimization_model_part.AddNodalSolutionStepVariable(KSO.CORRECTION)
|
|
77
|
+
|
|
78
|
+
# --------------------------------------------------------------------------
|
|
79
|
+
def CheckApplicability(self):
|
|
80
|
+
if self.objectives.size() > 1:
|
|
81
|
+
raise RuntimeError("Gradient projection algorithm only supports one objective function!")
|
|
82
|
+
if self.constraints.size() == 0:
|
|
83
|
+
raise RuntimeError("Gradient projection algorithm requires definition of at least one constraint!")
|
|
84
|
+
|
|
85
|
+
# --------------------------------------------------------------------------
|
|
86
|
+
def InitializeOptimizationLoop(self):
|
|
87
|
+
self.model_part_controller.Initialize()
|
|
88
|
+
|
|
89
|
+
self.analyzer.InitializeBeforeOptimizationLoop()
|
|
90
|
+
|
|
91
|
+
self.design_surface = self.model_part_controller.GetDesignSurface()
|
|
92
|
+
|
|
93
|
+
self.mapper = mapper_factory.CreateMapper(self.design_surface, self.design_surface, self.mapper_settings)
|
|
94
|
+
self.mapper.Initialize()
|
|
95
|
+
self.model_part_controller.InitializeDamping()
|
|
96
|
+
|
|
97
|
+
self.data_logger = data_logger_factory.CreateDataLogger(self.model_part_controller, self.communicator, self.optimization_settings)
|
|
98
|
+
self.data_logger.InitializeDataLogging()
|
|
99
|
+
|
|
100
|
+
self.optimization_utilities = KSO.OptimizationUtilities
|
|
101
|
+
|
|
102
|
+
# --------------------------------------------------------------------------
|
|
103
|
+
def RunOptimizationLoop(self):
|
|
104
|
+
timer = Timer()
|
|
105
|
+
timer.StartTimer()
|
|
106
|
+
|
|
107
|
+
for self.optimization_iteration in range(1,self.max_iterations):
|
|
108
|
+
KM.Logger.Print("")
|
|
109
|
+
KM.Logger.Print("===============================================================================")
|
|
110
|
+
KM.Logger.PrintInfo("ShapeOpt", timer.GetTimeStamp(), ": Starting optimization iteration ", self.optimization_iteration)
|
|
111
|
+
KM.Logger.Print("===============================================================================\n")
|
|
112
|
+
|
|
113
|
+
timer.StartNewLap()
|
|
114
|
+
|
|
115
|
+
self.__initializeNewShape()
|
|
116
|
+
|
|
117
|
+
self.__analyzeShape()
|
|
118
|
+
|
|
119
|
+
self.__computeShapeUpdate()
|
|
120
|
+
|
|
121
|
+
self.__logCurrentOptimizationStep()
|
|
122
|
+
|
|
123
|
+
KM.Logger.Print("")
|
|
124
|
+
KM.Logger.PrintInfo("ShapeOpt", "Time needed for current optimization step = ", timer.GetLapTime(), "s")
|
|
125
|
+
KM.Logger.PrintInfo("ShapeOpt", "Time needed for total optimization so far = ", timer.GetTotalTime(), "s")
|
|
126
|
+
|
|
127
|
+
if self.__isAlgorithmConverged():
|
|
128
|
+
break
|
|
129
|
+
else:
|
|
130
|
+
self.__determineAbsoluteChanges()
|
|
131
|
+
|
|
132
|
+
# --------------------------------------------------------------------------
|
|
133
|
+
def FinalizeOptimizationLoop(self):
|
|
134
|
+
self.data_logger.FinalizeDataLogging()
|
|
135
|
+
self.analyzer.FinalizeAfterOptimizationLoop()
|
|
136
|
+
|
|
137
|
+
# --------------------------------------------------------------------------
|
|
138
|
+
def __initializeNewShape(self):
|
|
139
|
+
self.model_part_controller.UpdateTimeStep(self.optimization_iteration)
|
|
140
|
+
self.model_part_controller.UpdateMeshAccordingInputVariable(KSO.SHAPE_UPDATE)
|
|
141
|
+
self.model_part_controller.SetReferenceMeshToMesh()
|
|
142
|
+
|
|
143
|
+
# --------------------------------------------------------------------------
|
|
144
|
+
def __analyzeShape(self):
|
|
145
|
+
self.communicator.initializeCommunication()
|
|
146
|
+
self.communicator.requestValueOf(self.objectives[0]["identifier"].GetString())
|
|
147
|
+
self.communicator.requestGradientOf(self.objectives[0]["identifier"].GetString())
|
|
148
|
+
|
|
149
|
+
for constraint in self.constraints.values():
|
|
150
|
+
con_id = constraint["identifier"].GetString()
|
|
151
|
+
self.communicator.requestValueOf(con_id)
|
|
152
|
+
self.communicator.requestGradientOf(con_id)
|
|
153
|
+
|
|
154
|
+
self.analyzer.AnalyzeDesignAndReportToCommunicator(self.optimization_model_part, self.optimization_iteration, self.communicator)
|
|
155
|
+
|
|
156
|
+
# compute normals only if required
|
|
157
|
+
surface_normals_required = self.objectives[0]["project_gradient_on_surface_normals"].GetBool()
|
|
158
|
+
for constraint in self.constraints.values():
|
|
159
|
+
if constraint["project_gradient_on_surface_normals"].GetBool():
|
|
160
|
+
surface_normals_required = True
|
|
161
|
+
|
|
162
|
+
if surface_normals_required:
|
|
163
|
+
self.model_part_controller.ComputeUnitSurfaceNormals()
|
|
164
|
+
|
|
165
|
+
# project and damp objective gradients
|
|
166
|
+
objGradientDict = self.communicator.getStandardizedGradient(self.objectives[0]["identifier"].GetString())
|
|
167
|
+
WriteDictionaryDataOnNodalVariable(objGradientDict, self.optimization_model_part, KSO.DF1DX)
|
|
168
|
+
|
|
169
|
+
if self.objectives[0]["project_gradient_on_surface_normals"].GetBool():
|
|
170
|
+
self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(KSO.DF1DX)
|
|
171
|
+
|
|
172
|
+
self.model_part_controller.DampNodalSensitivityVariableIfSpecified(KSO.DF1DX)
|
|
173
|
+
|
|
174
|
+
# project and damp constraint gradients
|
|
175
|
+
for constraint in self.constraints.values():
|
|
176
|
+
con_id = constraint["identifier"].GetString()
|
|
177
|
+
conGradientDict = self.communicator.getStandardizedGradient(con_id)
|
|
178
|
+
gradient_variable = self.constraint_gradient_variables[con_id]["gradient"]
|
|
179
|
+
WriteDictionaryDataOnNodalVariable(conGradientDict, self.optimization_model_part, gradient_variable)
|
|
180
|
+
|
|
181
|
+
if constraint["project_gradient_on_surface_normals"].GetBool():
|
|
182
|
+
self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(gradient_variable)
|
|
183
|
+
|
|
184
|
+
self.model_part_controller.DampNodalSensitivityVariableIfSpecified(gradient_variable)
|
|
185
|
+
|
|
186
|
+
# --------------------------------------------------------------------------
|
|
187
|
+
def __computeShapeUpdate(self):
|
|
188
|
+
self.mapper.Update()
|
|
189
|
+
self.mapper.InverseMap(KSO.DF1DX, KSO.DF1DX_MAPPED)
|
|
190
|
+
|
|
191
|
+
for constraint in self.constraints.values():
|
|
192
|
+
con_id = constraint["identifier"].GetString()
|
|
193
|
+
gradient_variable = self.constraint_gradient_variables[con_id]["gradient"]
|
|
194
|
+
mapped_gradient_variable = self.constraint_gradient_variables[con_id]["mapped_gradient"]
|
|
195
|
+
self.mapper.InverseMap(gradient_variable, mapped_gradient_variable)
|
|
196
|
+
|
|
197
|
+
self.__computeControlPointUpdate()
|
|
198
|
+
|
|
199
|
+
self.mapper.Map(KSO.CONTROL_POINT_UPDATE, KSO.SHAPE_UPDATE)
|
|
200
|
+
self.model_part_controller.DampNodalUpdateVariableIfSpecified(KSO.SHAPE_UPDATE)
|
|
201
|
+
|
|
202
|
+
# --------------------------------------------------------------------------
|
|
203
|
+
def __computeControlPointUpdate(self):
|
|
204
|
+
"""adapted from https://msulaiman.org/onewebmedia/GradProj_2.pdf"""
|
|
205
|
+
g_a, g_a_variables = self.__getActiveConstraints()
|
|
206
|
+
|
|
207
|
+
KM.Logger.PrintInfo("ShapeOpt", "Assemble vector of objective gradient.")
|
|
208
|
+
nabla_f = KM.Vector()
|
|
209
|
+
s = KM.Vector()
|
|
210
|
+
self.optimization_utilities.AssembleVector(self.design_surface, nabla_f, KSO.DF1DX_MAPPED)
|
|
211
|
+
|
|
212
|
+
if len(g_a) == 0:
|
|
213
|
+
KM.Logger.PrintInfo("ShapeOpt", "No constraints active, use negative objective gradient as search direction.")
|
|
214
|
+
s = nabla_f * (-1.0)
|
|
215
|
+
s *= self.step_size / s.norm_inf()
|
|
216
|
+
self.optimization_utilities.AssignVectorToVariable(self.design_surface, s, KSO.SEARCH_DIRECTION)
|
|
217
|
+
self.optimization_utilities.AssignVectorToVariable(self.design_surface, [0.0]*len(s), KSO.CORRECTION)
|
|
218
|
+
self.optimization_utilities.AssignVectorToVariable(self.design_surface, s, KSO.CONTROL_POINT_UPDATE)
|
|
219
|
+
return
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
KM.Logger.PrintInfo("ShapeOpt", "Assemble matrix of constraint gradient.")
|
|
223
|
+
N = KM.Matrix()
|
|
224
|
+
self.optimization_utilities.AssembleMatrix(self.design_surface, N, g_a_variables)
|
|
225
|
+
|
|
226
|
+
settings = KM.Parameters('{ "solver_type" : "LinearSolversApplication.dense_col_piv_householder_qr" }')
|
|
227
|
+
solver = dense_linear_solver_factory.ConstructSolver(settings)
|
|
228
|
+
|
|
229
|
+
KM.Logger.PrintInfo("ShapeOpt", "Calculate projected search direction and correction.")
|
|
230
|
+
c = KM.Vector()
|
|
231
|
+
self.optimization_utilities.CalculateProjectedSearchDirectionAndCorrection(
|
|
232
|
+
nabla_f,
|
|
233
|
+
N,
|
|
234
|
+
g_a,
|
|
235
|
+
solver,
|
|
236
|
+
s,
|
|
237
|
+
c)
|
|
238
|
+
|
|
239
|
+
if c.norm_inf() != 0.0:
|
|
240
|
+
if c.norm_inf() <= self.max_correction_share * self.step_size:
|
|
241
|
+
delta = self.step_size - c.norm_inf()
|
|
242
|
+
s *= delta/s.norm_inf()
|
|
243
|
+
else:
|
|
244
|
+
KM.Logger.PrintWarning("ShapeOpt", f"Correction is scaled down from {c.norm_inf()} to {self.max_correction_share * self.step_size}.")
|
|
245
|
+
c *= self.max_correction_share * self.step_size / c.norm_inf()
|
|
246
|
+
s *= (1.0 - self.max_correction_share) * self.step_size / s.norm_inf()
|
|
247
|
+
else:
|
|
248
|
+
s *= self.step_size / s.norm_inf()
|
|
249
|
+
|
|
250
|
+
self.optimization_utilities.AssignVectorToVariable(self.design_surface, s, KSO.SEARCH_DIRECTION)
|
|
251
|
+
self.optimization_utilities.AssignVectorToVariable(self.design_surface, c, KSO.CORRECTION)
|
|
252
|
+
self.optimization_utilities.AssignVectorToVariable(self.design_surface, s+c, KSO.CONTROL_POINT_UPDATE)
|
|
253
|
+
|
|
254
|
+
# --------------------------------------------------------------------------
|
|
255
|
+
def __getActiveConstraints(self):
|
|
256
|
+
active_constraint_values = []
|
|
257
|
+
active_constraint_variables = []
|
|
258
|
+
|
|
259
|
+
for constraint in self.constraints.values():
|
|
260
|
+
if self.__isConstraintActive(constraint):
|
|
261
|
+
identifier = constraint["identifier"].GetString()
|
|
262
|
+
constraint_value = self.communicator.getStandardizedValue(identifier)
|
|
263
|
+
active_constraint_values.append(constraint_value)
|
|
264
|
+
active_constraint_variables.append(
|
|
265
|
+
self.constraint_gradient_variables[identifier]["mapped_gradient"])
|
|
266
|
+
|
|
267
|
+
return active_constraint_values, active_constraint_variables
|
|
268
|
+
|
|
269
|
+
# --------------------------------------------------------------------------
|
|
270
|
+
def __isConstraintActive(self, constraint):
|
|
271
|
+
identifier = constraint["identifier"].GetString()
|
|
272
|
+
constraint_value = self.communicator.getStandardizedValue(identifier)
|
|
273
|
+
if constraint["type"].GetString() == "=" or constraint_value >= 0:
|
|
274
|
+
gradient_norm = self.optimization_utilities.ComputeMaxNormOfNodalVariable(
|
|
275
|
+
self.design_surface, self.constraint_gradient_variables[identifier]["mapped_gradient"]
|
|
276
|
+
)
|
|
277
|
+
if math.isclose(gradient_norm, 0.0, abs_tol=1e-16):
|
|
278
|
+
KM.Logger.PrintWarning("ShapeOpt", f"Gradient for constraint {identifier} is 0.0 - will not be considered!")
|
|
279
|
+
return False
|
|
280
|
+
return True
|
|
281
|
+
else:
|
|
282
|
+
return False
|
|
283
|
+
|
|
284
|
+
# --------------------------------------------------------------------------
|
|
285
|
+
def __logCurrentOptimizationStep(self):
|
|
286
|
+
additional_values_to_log = {}
|
|
287
|
+
additional_values_to_log["step_size"] = self.step_size
|
|
288
|
+
additional_values_to_log["inf_norm_s"] = self.optimization_utilities.ComputeMaxNormOfNodalVariable(self.design_surface, KSO.SEARCH_DIRECTION)
|
|
289
|
+
additional_values_to_log["inf_norm_c"] = self.optimization_utilities.ComputeMaxNormOfNodalVariable(self.design_surface, KSO.CORRECTION)
|
|
290
|
+
self.data_logger.LogSensitivityHeatmap(self.optimization_iteration, self.mapper)
|
|
291
|
+
self.data_logger.LogCurrentValues(self.optimization_iteration, additional_values_to_log)
|
|
292
|
+
self.data_logger.LogCurrentDesign(self.optimization_iteration)
|
|
293
|
+
|
|
294
|
+
# --------------------------------------------------------------------------
|
|
295
|
+
def __isAlgorithmConverged(self):
|
|
296
|
+
|
|
297
|
+
if self.optimization_iteration > 1 :
|
|
298
|
+
|
|
299
|
+
# Check if maximum iterations were reached
|
|
300
|
+
if self.optimization_iteration == self.max_iterations:
|
|
301
|
+
KM.Logger.Print("")
|
|
302
|
+
KM.Logger.PrintInfo("ShapeOpt", "Maximal iterations of optimization problem reached!")
|
|
303
|
+
return True
|
|
304
|
+
|
|
305
|
+
# Check for relative tolerance
|
|
306
|
+
relative_change_of_objective_value = self.data_logger.GetValues("rel_change_objective")[self.optimization_iteration]
|
|
307
|
+
if abs(relative_change_of_objective_value) < self.relative_tolerance:
|
|
308
|
+
KM.Logger.Print("")
|
|
309
|
+
KM.Logger.PrintInfo("ShapeOpt", "Optimization problem converged within a relative objective tolerance of ",self.relative_tolerance,"%.")
|
|
310
|
+
return True
|
|
311
|
+
|
|
312
|
+
# --------------------------------------------------------------------------
|
|
313
|
+
def __determineAbsoluteChanges(self):
|
|
314
|
+
self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.CONTROL_POINT_UPDATE, KSO.CONTROL_POINT_CHANGE)
|
|
315
|
+
self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.SHAPE_UPDATE, KSO.SHAPE_CHANGE)
|
|
316
|
+
|
|
317
|
+
# ==============================================================================
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# KratosShapeOptimizationApplication
|
|
3
|
+
#
|
|
4
|
+
# License: BSD License
|
|
5
|
+
# license: ShapeOptimizationApplication/license.txt
|
|
6
|
+
#
|
|
7
|
+
# Main authors: Baumgaertner Daniel, https://github.com/dbaumgaertner
|
|
8
|
+
# Geiser Armin, https://github.com/armingeiser
|
|
9
|
+
#
|
|
10
|
+
# ==============================================================================
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Kratos Core and Apps
|
|
14
|
+
import KratosMultiphysics as KM
|
|
15
|
+
import KratosMultiphysics.ShapeOptimizationApplication as KSO
|
|
16
|
+
|
|
17
|
+
# Additional imports
|
|
18
|
+
from KratosMultiphysics.ShapeOptimizationApplication.algorithms.algorithm_base import OptimizationAlgorithm
|
|
19
|
+
from KratosMultiphysics.ShapeOptimizationApplication import mapper_factory
|
|
20
|
+
from KratosMultiphysics.ShapeOptimizationApplication.loggers import data_logger_factory
|
|
21
|
+
from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_timer import Timer
|
|
22
|
+
from KratosMultiphysics.ShapeOptimizationApplication.utilities.custom_variable_utilities import WriteDictionaryDataOnNodalVariable
|
|
23
|
+
|
|
24
|
+
# ==============================================================================
|
|
25
|
+
class AlgorithmPenalizedProjection(OptimizationAlgorithm):
|
|
26
|
+
# --------------------------------------------------------------------------
|
|
27
|
+
def __init__(self, optimization_settings, analyzer, communicator, model_part_controller):
|
|
28
|
+
default_algorithm_settings = KM.Parameters("""
|
|
29
|
+
{
|
|
30
|
+
"name" : "penalized_projection",
|
|
31
|
+
"correction_scaling" : 1.0,
|
|
32
|
+
"use_adaptive_correction" : true,
|
|
33
|
+
"max_iterations" : 100,
|
|
34
|
+
"relative_tolerance" : 1e-3,
|
|
35
|
+
"line_search" : {
|
|
36
|
+
"line_search_type" : "manual_stepping",
|
|
37
|
+
"normalize_search_direction" : true,
|
|
38
|
+
"step_size" : 1.0
|
|
39
|
+
}
|
|
40
|
+
}""")
|
|
41
|
+
self.algorithm_settings = optimization_settings["optimization_algorithm"]
|
|
42
|
+
self.algorithm_settings.RecursivelyValidateAndAssignDefaults(default_algorithm_settings)
|
|
43
|
+
|
|
44
|
+
self.optimization_settings = optimization_settings
|
|
45
|
+
self.mapper_settings = optimization_settings["design_variables"]["filter"]
|
|
46
|
+
|
|
47
|
+
self.analyzer = analyzer
|
|
48
|
+
self.communicator = communicator
|
|
49
|
+
self.model_part_controller = model_part_controller
|
|
50
|
+
|
|
51
|
+
self.design_surface = None
|
|
52
|
+
self.mapper = None
|
|
53
|
+
self.data_logger = None
|
|
54
|
+
self.optimization_utilities = None
|
|
55
|
+
self.constraint_value = 0.0
|
|
56
|
+
self.correction_scaling = optimization_settings["optimization_algorithm"]["correction_scaling"].GetDouble()
|
|
57
|
+
|
|
58
|
+
self.objectives = optimization_settings["objectives"]
|
|
59
|
+
self.constraints = optimization_settings["constraints"]
|
|
60
|
+
|
|
61
|
+
self.step_size = self.algorithm_settings["line_search"]["step_size"].GetDouble()
|
|
62
|
+
self.max_iterations = self.algorithm_settings["max_iterations"].GetInt() + 1
|
|
63
|
+
self.relative_tolerance = self.algorithm_settings["relative_tolerance"].GetDouble()
|
|
64
|
+
|
|
65
|
+
self.optimization_model_part = model_part_controller.GetOptimizationModelPart()
|
|
66
|
+
self.optimization_model_part.AddNodalSolutionStepVariable(KSO.SEARCH_DIRECTION)
|
|
67
|
+
|
|
68
|
+
# --------------------------------------------------------------------------
|
|
69
|
+
def CheckApplicability(self):
|
|
70
|
+
if self.objectives.size() > 1:
|
|
71
|
+
raise RuntimeError("Penalized projection algorithm only supports one objective function!")
|
|
72
|
+
if self.constraints.size() == 0:
|
|
73
|
+
raise RuntimeError("Penalized projection algorithm requires definition of a constraint!")
|
|
74
|
+
if self.constraints.size() > 1:
|
|
75
|
+
raise RuntimeError("Penalized projection algorithm only supports one constraint!")
|
|
76
|
+
|
|
77
|
+
# --------------------------------------------------------------------------
|
|
78
|
+
def InitializeOptimizationLoop(self):
|
|
79
|
+
self.model_part_controller.Initialize()
|
|
80
|
+
|
|
81
|
+
self.analyzer.InitializeBeforeOptimizationLoop()
|
|
82
|
+
|
|
83
|
+
self.design_surface = self.model_part_controller.GetDesignSurface()
|
|
84
|
+
|
|
85
|
+
self.mapper = mapper_factory.CreateMapper(self.design_surface, self.design_surface, self.mapper_settings)
|
|
86
|
+
self.mapper.Initialize()
|
|
87
|
+
self.model_part_controller.InitializeDamping()
|
|
88
|
+
|
|
89
|
+
self.data_logger = data_logger_factory.CreateDataLogger(self.model_part_controller, self.communicator, self.optimization_settings)
|
|
90
|
+
self.data_logger.InitializeDataLogging()
|
|
91
|
+
|
|
92
|
+
self.optimization_utilities = KSO.OptimizationUtilities
|
|
93
|
+
|
|
94
|
+
# --------------------------------------------------------------------------
|
|
95
|
+
def RunOptimizationLoop(self):
|
|
96
|
+
timer = Timer()
|
|
97
|
+
timer.StartTimer()
|
|
98
|
+
|
|
99
|
+
for self.optimization_iteration in range(1,self.max_iterations):
|
|
100
|
+
KM.Logger.Print("")
|
|
101
|
+
KM.Logger.Print("===============================================================================")
|
|
102
|
+
KM.Logger.PrintInfo("ShapeOpt", timer.GetTimeStamp(), ": Starting optimization iteration ", self.optimization_iteration)
|
|
103
|
+
KM.Logger.Print("===============================================================================\n")
|
|
104
|
+
|
|
105
|
+
timer.StartNewLap()
|
|
106
|
+
|
|
107
|
+
self.__initializeNewShape()
|
|
108
|
+
|
|
109
|
+
self.__analyzeShape()
|
|
110
|
+
|
|
111
|
+
self.__computeShapeUpdate()
|
|
112
|
+
|
|
113
|
+
self.__logCurrentOptimizationStep()
|
|
114
|
+
|
|
115
|
+
KM.Logger.Print("")
|
|
116
|
+
KM.Logger.PrintInfo("ShapeOpt", "Time needed for current optimization step = ", timer.GetLapTime(), "s")
|
|
117
|
+
KM.Logger.PrintInfo("ShapeOpt", "Time needed for total optimization so far = ", timer.GetTotalTime(), "s")
|
|
118
|
+
|
|
119
|
+
if self.__isAlgorithmConverged():
|
|
120
|
+
break
|
|
121
|
+
else:
|
|
122
|
+
self.__determineAbsoluteChanges()
|
|
123
|
+
|
|
124
|
+
# --------------------------------------------------------------------------
|
|
125
|
+
def FinalizeOptimizationLoop(self):
|
|
126
|
+
self.data_logger.FinalizeDataLogging()
|
|
127
|
+
self.analyzer.FinalizeAfterOptimizationLoop()
|
|
128
|
+
|
|
129
|
+
# --------------------------------------------------------------------------
|
|
130
|
+
def __initializeNewShape(self):
|
|
131
|
+
self.model_part_controller.UpdateTimeStep(self.optimization_iteration)
|
|
132
|
+
self.model_part_controller.UpdateMeshAccordingInputVariable(KSO.SHAPE_UPDATE)
|
|
133
|
+
self.model_part_controller.SetReferenceMeshToMesh()
|
|
134
|
+
|
|
135
|
+
# --------------------------------------------------------------------------
|
|
136
|
+
def __analyzeShape(self):
|
|
137
|
+
self.communicator.initializeCommunication()
|
|
138
|
+
self.communicator.requestValueOf(self.objectives[0]["identifier"].GetString())
|
|
139
|
+
self.communicator.requestGradientOf(self.objectives[0]["identifier"].GetString())
|
|
140
|
+
self.communicator.requestValueOf(self.constraints[0]["identifier"].GetString())
|
|
141
|
+
self.communicator.requestGradientOf(self.constraints[0]["identifier"].GetString())
|
|
142
|
+
|
|
143
|
+
self.analyzer.AnalyzeDesignAndReportToCommunicator(self.optimization_model_part, self.optimization_iteration, self.communicator)
|
|
144
|
+
|
|
145
|
+
objGradientDict = self.communicator.getStandardizedGradient(self.objectives[0]["identifier"].GetString())
|
|
146
|
+
conGradientDict = self.communicator.getStandardizedGradient(self.constraints[0]["identifier"].GetString())
|
|
147
|
+
|
|
148
|
+
WriteDictionaryDataOnNodalVariable(objGradientDict, self.optimization_model_part, KSO.DF1DX)
|
|
149
|
+
WriteDictionaryDataOnNodalVariable(conGradientDict, self.optimization_model_part, KSO.DC1DX)
|
|
150
|
+
|
|
151
|
+
if self.objectives[0]["project_gradient_on_surface_normals"].GetBool() or self.constraints[0]["project_gradient_on_surface_normals"].GetBool():
|
|
152
|
+
self.model_part_controller.ComputeUnitSurfaceNormals()
|
|
153
|
+
|
|
154
|
+
if self.objectives[0]["project_gradient_on_surface_normals"].GetBool():
|
|
155
|
+
self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(KSO.DF1DX)
|
|
156
|
+
|
|
157
|
+
if self.constraints[0]["project_gradient_on_surface_normals"].GetBool():
|
|
158
|
+
self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(KSO.DC1DX)
|
|
159
|
+
|
|
160
|
+
self.model_part_controller.DampNodalSensitivityVariableIfSpecified(KSO.DF1DX)
|
|
161
|
+
self.model_part_controller.DampNodalSensitivityVariableIfSpecified(KSO.DC1DX)
|
|
162
|
+
|
|
163
|
+
# --------------------------------------------------------------------------
|
|
164
|
+
def __computeShapeUpdate(self):
|
|
165
|
+
self.mapper.Update()
|
|
166
|
+
self.mapper.InverseMap(KSO.DF1DX, KSO.DF1DX_MAPPED)
|
|
167
|
+
self.mapper.InverseMap(KSO.DC1DX, KSO.DC1DX_MAPPED)
|
|
168
|
+
is_adaptive = self.algorithm_settings["use_adaptive_correction"].GetBool()
|
|
169
|
+
|
|
170
|
+
constraint_value = self.communicator.getStandardizedValue(self.constraints[0]["identifier"].GetString())
|
|
171
|
+
if self.__isConstraintActive(constraint_value):
|
|
172
|
+
self.optimization_utilities.ComputeProjectedSearchDirection(self.design_surface)
|
|
173
|
+
self.correction_scaling = self.optimization_utilities.CorrectProjectedSearchDirection(self.design_surface, self.constraint_value, constraint_value, self.correction_scaling, is_adaptive)
|
|
174
|
+
self.constraint_value = constraint_value
|
|
175
|
+
else:
|
|
176
|
+
self.optimization_utilities.ComputeSearchDirectionSteepestDescent(self.design_surface)
|
|
177
|
+
|
|
178
|
+
normalize = self.algorithm_settings["line_search"]["normalize_search_direction"].GetBool()
|
|
179
|
+
self.optimization_utilities.ComputeControlPointUpdate(self.design_surface, self.step_size, normalize)
|
|
180
|
+
|
|
181
|
+
self.mapper.Map(KSO.CONTROL_POINT_UPDATE, KSO.SHAPE_UPDATE)
|
|
182
|
+
self.model_part_controller.DampNodalUpdateVariableIfSpecified(KSO.SHAPE_UPDATE)
|
|
183
|
+
|
|
184
|
+
# --------------------------------------------------------------------------
|
|
185
|
+
def __isConstraintActive(self, constraintValue):
|
|
186
|
+
if self.constraints[0]["type"].GetString() == "=":
|
|
187
|
+
return True
|
|
188
|
+
elif constraintValue > 0:
|
|
189
|
+
return True
|
|
190
|
+
else:
|
|
191
|
+
return False
|
|
192
|
+
|
|
193
|
+
# --------------------------------------------------------------------------
|
|
194
|
+
def __logCurrentOptimizationStep(self):
|
|
195
|
+
additional_values_to_log = {}
|
|
196
|
+
additional_values_to_log["correction_scaling"] = self.correction_scaling
|
|
197
|
+
additional_values_to_log["step_size"] = self.step_size
|
|
198
|
+
self.data_logger.LogSensitivityHeatmap(self.optimization_iteration, self.mapper)
|
|
199
|
+
self.data_logger.LogCurrentValues(self.optimization_iteration, additional_values_to_log)
|
|
200
|
+
self.data_logger.LogCurrentDesign(self.optimization_iteration)
|
|
201
|
+
|
|
202
|
+
# --------------------------------------------------------------------------
|
|
203
|
+
def __isAlgorithmConverged(self):
|
|
204
|
+
|
|
205
|
+
if self.optimization_iteration > 1 :
|
|
206
|
+
|
|
207
|
+
# Check if maximum iterations were reached
|
|
208
|
+
if self.optimization_iteration == self.max_iterations:
|
|
209
|
+
KM.Logger.Print("")
|
|
210
|
+
KM.Logger.PrintInfo("ShapeOpt", "Maximal iterations of optimization problem reached!")
|
|
211
|
+
return True
|
|
212
|
+
|
|
213
|
+
# Check for relative tolerance
|
|
214
|
+
relative_change_of_objective_value = self.data_logger.GetValues("rel_change_objective")[self.optimization_iteration]
|
|
215
|
+
if abs(relative_change_of_objective_value) < self.relative_tolerance:
|
|
216
|
+
KM.Logger.Print("")
|
|
217
|
+
KM.Logger.PrintInfo("ShapeOpt", "Optimization problem converged within a relative objective tolerance of ",self.relative_tolerance,"%.")
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
# --------------------------------------------------------------------------
|
|
221
|
+
def __determineAbsoluteChanges(self):
|
|
222
|
+
self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.CONTROL_POINT_UPDATE, KSO.CONTROL_POINT_CHANGE)
|
|
223
|
+
self.optimization_utilities.AddFirstVariableToSecondVariable(self.design_surface, KSO.SHAPE_UPDATE, KSO.SHAPE_CHANGE)
|
|
224
|
+
|
|
225
|
+
# ==============================================================================
|