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
KratosMultiphysics/ShapeOptimizationApplication/response_functions/surface_normal_shape_change.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# KratosShapeOptimizationApplication
|
|
3
|
+
#
|
|
4
|
+
# License: BSD License
|
|
5
|
+
# license: ShapeOptimizationApplication/license.txt
|
|
6
|
+
#
|
|
7
|
+
# Main authors: Geiser Armin, https://github.com/armingeiser
|
|
8
|
+
#
|
|
9
|
+
# ==============================================================================
|
|
10
|
+
|
|
11
|
+
import time as timer
|
|
12
|
+
import KratosMultiphysics as KM
|
|
13
|
+
import KratosMultiphysics.ShapeOptimizationApplication as KSO
|
|
14
|
+
from KratosMultiphysics import Logger
|
|
15
|
+
from KratosMultiphysics.response_functions.response_function_interface import ResponseFunctionInterface
|
|
16
|
+
|
|
17
|
+
class SurfaceNormalShapeChange(ResponseFunctionInterface):
|
|
18
|
+
"""
|
|
19
|
+
This simple geometric response function calculates the sum of all shape updates in
|
|
20
|
+
surface normal direction. Shape update in surface normal direction is considered positive,
|
|
21
|
+
in the opposite direction negative.
|
|
22
|
+
|
|
23
|
+
Note that the direction of the surface normals changes in every step,
|
|
24
|
+
this is why the response value is not a meaningful measure but only an indication on how much the shape changed.
|
|
25
|
+
|
|
26
|
+
Important settings:
|
|
27
|
+
flip_normal_direction : boolean flag for changing on which side of the surface the update is considered positive.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, identifier, response_settings, model):
|
|
31
|
+
self.identifier = identifier
|
|
32
|
+
|
|
33
|
+
response_settings.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
34
|
+
|
|
35
|
+
self.response_settings = response_settings
|
|
36
|
+
self.model = model
|
|
37
|
+
|
|
38
|
+
self._model_part_name = response_settings["model_part_name"].GetString()
|
|
39
|
+
input_type = response_settings["model_import_settings"]["input_type"].GetString()
|
|
40
|
+
if input_type == "mdpa":
|
|
41
|
+
self.model_part = self.model.CreateModelPart(self._model_part_name)
|
|
42
|
+
domain_size = response_settings["domain_size"].GetInt()
|
|
43
|
+
if domain_size not in [2, 3]:
|
|
44
|
+
raise Exception("SurfaceNormalShapeChange: Invalid 'domain_size': {}".format(domain_size))
|
|
45
|
+
self.model_part.ProcessInfo.SetValue(KM.DOMAIN_SIZE, domain_size)
|
|
46
|
+
elif input_type == "use_input_model_part":
|
|
47
|
+
self.model_part = None # will be retrieved in Initialize()
|
|
48
|
+
else:
|
|
49
|
+
raise Exception("SurfaceNormalShapeChange: '{}' model part input type not implemented.".format(input_type))
|
|
50
|
+
|
|
51
|
+
self.signed_distances = None
|
|
52
|
+
self.directions = None
|
|
53
|
+
|
|
54
|
+
self.previous_value = 0.0
|
|
55
|
+
self.value = 0.0
|
|
56
|
+
|
|
57
|
+
self.gradient = {}
|
|
58
|
+
|
|
59
|
+
self.flip_normal_direction = self.response_settings["flip_normal_direction"].GetBool()
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def GetDefaultParameters(cls):
|
|
63
|
+
this_defaults = KM.Parameters("""{
|
|
64
|
+
"response_type" : "surface_normal_shape_change",
|
|
65
|
+
"model_part_name" : "UNKNOWN_NAME",
|
|
66
|
+
"domain_size" : 3,
|
|
67
|
+
"model_import_settings" : {
|
|
68
|
+
"input_type" : "use_input_model_part",
|
|
69
|
+
"input_filename" : "UNKNOWN_NAME"
|
|
70
|
+
},
|
|
71
|
+
"flip_normal_direction" : false
|
|
72
|
+
}""")
|
|
73
|
+
return this_defaults
|
|
74
|
+
|
|
75
|
+
def Initialize(self):
|
|
76
|
+
if self.response_settings["model_import_settings"]["input_type"].GetString() == "mdpa":
|
|
77
|
+
file_name = self.response_settings["model_import_settings"]["input_filename"].GetString()
|
|
78
|
+
model_part_io = KM.ModelPartIO(file_name)
|
|
79
|
+
model_part_io.ReadModelPart(self.model_part)
|
|
80
|
+
else:
|
|
81
|
+
self.model_part = self.model.GetModelPart(self._model_part_name)
|
|
82
|
+
|
|
83
|
+
def InitializeSolutionStep(self):
|
|
84
|
+
self.previous_value = self.value
|
|
85
|
+
self.value = None
|
|
86
|
+
self.gradient = {}
|
|
87
|
+
KSO.GeometryUtilities(self.model_part).ComputeUnitSurfaceNormals()
|
|
88
|
+
|
|
89
|
+
def CalculateValue(self):
|
|
90
|
+
Logger.PrintInfo("\n> Starting primal analysis for response", self.identifier)
|
|
91
|
+
|
|
92
|
+
startTime = timer.time()
|
|
93
|
+
|
|
94
|
+
value = 0.0
|
|
95
|
+
for node in self.model_part.Nodes:
|
|
96
|
+
shape_update = node.GetSolutionStepValue(KSO.SHAPE_UPDATE)
|
|
97
|
+
normalized_normal = node.GetSolutionStepValue(KSO.NORMALIZED_SURFACE_NORMAL)
|
|
98
|
+
value += shape_update[0] * normalized_normal[0]
|
|
99
|
+
value += shape_update[1] * normalized_normal[1]
|
|
100
|
+
value += shape_update[2] * normalized_normal[2]
|
|
101
|
+
|
|
102
|
+
self.value = value + self.previous_value
|
|
103
|
+
|
|
104
|
+
Logger.PrintInfo("> Time needed for calculating the response value = ", round(timer.time() - startTime,2), "s")
|
|
105
|
+
|
|
106
|
+
def CalculateGradient(self):
|
|
107
|
+
Logger.PrintInfo("\n> Starting gradient calculation for response", self.identifier)
|
|
108
|
+
|
|
109
|
+
startTime = timer.time()
|
|
110
|
+
|
|
111
|
+
for node in self.model_part.Nodes:
|
|
112
|
+
normalized_normal = node.GetSolutionStepValue(KSO.NORMALIZED_SURFACE_NORMAL)
|
|
113
|
+
self.gradient[node.Id] = normalized_normal
|
|
114
|
+
|
|
115
|
+
Logger.PrintInfo("> Time needed for calculating gradients = ", round(timer.time() - startTime,2), "s")
|
|
116
|
+
|
|
117
|
+
def GetValue(self):
|
|
118
|
+
return self.value
|
|
119
|
+
|
|
120
|
+
def GetNodalGradient(self, variable):
|
|
121
|
+
if not self.gradient:
|
|
122
|
+
raise RuntimeError("Gradient was not calculated")
|
|
123
|
+
if variable != KM.SHAPE_SENSITIVITY:
|
|
124
|
+
raise RuntimeError("GetNodalGradient: No gradient for {}!".format(variable.Name))
|
|
125
|
+
return self.gradient
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains an interface to the total volume response function
|
|
3
|
+
"""
|
|
4
|
+
import time as timer
|
|
5
|
+
import KratosMultiphysics as Kratos
|
|
6
|
+
import KratosMultiphysics.ShapeOptimizationApplication as KSO
|
|
7
|
+
from KratosMultiphysics.response_functions.response_function_interface import ResponseFunctionInterface
|
|
8
|
+
|
|
9
|
+
class TotalVolume(ResponseFunctionInterface):
|
|
10
|
+
def __init__(self, identifier, response_settings, model):
|
|
11
|
+
self.identifier = identifier
|
|
12
|
+
self.response_settings = response_settings
|
|
13
|
+
|
|
14
|
+
default_parameters = Kratos.Parameters("""
|
|
15
|
+
{
|
|
16
|
+
"response_type" : "total_volume",
|
|
17
|
+
"model_part_name" : "PLEASE_SPECIFY_MODEL_PART_NAME"
|
|
18
|
+
}
|
|
19
|
+
""")
|
|
20
|
+
|
|
21
|
+
self.response_settings.ValidateAndAssignDefaults(default_parameters)
|
|
22
|
+
self.model = model
|
|
23
|
+
|
|
24
|
+
def Initialize(self):
|
|
25
|
+
self.model_part = self.model[self.response_settings["model_part_name"].GetString()]
|
|
26
|
+
|
|
27
|
+
def CalculateValue(self):
|
|
28
|
+
start_time = timer.time()
|
|
29
|
+
|
|
30
|
+
self.value = KSO.GeometryUtilities(self.model_part).ComputeVolume()
|
|
31
|
+
|
|
32
|
+
Kratos.Logger.PrintInfo(self._GetLabel(), "Time needed for calculating the response value = ",round(timer.time() - start_time,2),"s")
|
|
33
|
+
|
|
34
|
+
def CalculateGradient(self):
|
|
35
|
+
start_time = timer.time()
|
|
36
|
+
|
|
37
|
+
KSO.GeometryUtilities(self.model_part).ComputeVolumeShapeDerivatives(Kratos.SHAPE_SENSITIVITY)
|
|
38
|
+
self.gradient = {}
|
|
39
|
+
for node in self.model_part.Nodes:
|
|
40
|
+
self.gradient[node.Id] = node.GetSolutionStepValue(Kratos.SHAPE_SENSITIVITY)
|
|
41
|
+
|
|
42
|
+
Kratos.Logger.PrintInfo(self._GetLabel(), "Time needed for calculating the gradient = ",round(timer.time() - start_time,2),"s")
|
|
43
|
+
|
|
44
|
+
def GetValue(self):
|
|
45
|
+
return self.value
|
|
46
|
+
|
|
47
|
+
def GetNodalGradient(self, variable):
|
|
48
|
+
if variable != Kratos.SHAPE_SENSITIVITY:
|
|
49
|
+
raise RuntimeError("GetNodalGradient: No gradient for {}!".format(variable.Name))
|
|
50
|
+
return self.gradient
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def _GetLabel():
|
|
54
|
+
return "TotalVolume"
|
|
55
|
+
|
|
56
|
+
|
|
File without changes
|
|
@@ -0,0 +1,443 @@
|
|
|
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
|
+
# importing the Kratos Library
|
|
13
|
+
import KratosMultiphysics as KM
|
|
14
|
+
|
|
15
|
+
# Import additional libraries
|
|
16
|
+
import math
|
|
17
|
+
|
|
18
|
+
# ==============================================================================
|
|
19
|
+
def SafeConvertVectorToMatrix(_L):
|
|
20
|
+
if IsVector(_L):
|
|
21
|
+
return [_L]
|
|
22
|
+
else:
|
|
23
|
+
return _L
|
|
24
|
+
|
|
25
|
+
# ------------------------------------------------------------------------------
|
|
26
|
+
def IsVector(_X):
|
|
27
|
+
if len(_X)==0 or isinstance(_X[0],(float,int)):
|
|
28
|
+
return True
|
|
29
|
+
else:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
# ------------------------------------------------------------------------------
|
|
33
|
+
def IsEmpty(_A):
|
|
34
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
35
|
+
|
|
36
|
+
if len(_A)==0 or len(_A[0])==0:
|
|
37
|
+
return True
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
# ------------------------------------------------------------------------------
|
|
41
|
+
def ZeroVector(m):
|
|
42
|
+
return [0.0 for i in range(m)]
|
|
43
|
+
|
|
44
|
+
# ------------------------------------------------------------------------------
|
|
45
|
+
def ZeroMatrix(m,n):
|
|
46
|
+
A = [[0.0 for i in range(m)] for j in range(n)]
|
|
47
|
+
return A
|
|
48
|
+
|
|
49
|
+
# ------------------------------------------------------------------------------
|
|
50
|
+
def Ones(n):
|
|
51
|
+
return [1.0 for i in range(n)]
|
|
52
|
+
|
|
53
|
+
# ------------------------------------------------------------------------------
|
|
54
|
+
def RowSize(_A):
|
|
55
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
56
|
+
|
|
57
|
+
if len(_A)==0:
|
|
58
|
+
return 0
|
|
59
|
+
return len(_A[0])
|
|
60
|
+
|
|
61
|
+
# ------------------------------------------------------------------------------
|
|
62
|
+
def CollSize(_A):
|
|
63
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
64
|
+
|
|
65
|
+
return len(_A)
|
|
66
|
+
|
|
67
|
+
# ------------------------------------------------------------------------------
|
|
68
|
+
# horizontal concatenation
|
|
69
|
+
def HorzCat(_A,_B):
|
|
70
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
71
|
+
_B = SafeConvertVectorToMatrix(_B)
|
|
72
|
+
|
|
73
|
+
if IsEmpty(_B):
|
|
74
|
+
return _A
|
|
75
|
+
if IsEmpty(_A):
|
|
76
|
+
return _B
|
|
77
|
+
|
|
78
|
+
return _A+_B
|
|
79
|
+
|
|
80
|
+
# ------------------------------------------------------------------------------
|
|
81
|
+
# vertical concatenation
|
|
82
|
+
def VertCat(_A,_B):
|
|
83
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
84
|
+
_B = SafeConvertVectorToMatrix(_B)
|
|
85
|
+
|
|
86
|
+
if IsEmpty(_B):
|
|
87
|
+
return _A
|
|
88
|
+
if IsEmpty(_A):
|
|
89
|
+
return _B
|
|
90
|
+
|
|
91
|
+
coll_size_A = CollSize(_A)
|
|
92
|
+
coll_size_B = CollSize(_B)
|
|
93
|
+
|
|
94
|
+
if coll_size_A!=coll_size_B:
|
|
95
|
+
raise ValueError("custom_math::VertCat: Wrong size in vertical concatenation detected!")
|
|
96
|
+
|
|
97
|
+
_C = []
|
|
98
|
+
for i in range(coll_size_A):
|
|
99
|
+
_C.append(_A[i]+_B[i])
|
|
100
|
+
|
|
101
|
+
if CollSize(_C) == 1:
|
|
102
|
+
return _C[0]
|
|
103
|
+
else:
|
|
104
|
+
return _C
|
|
105
|
+
|
|
106
|
+
# ------------------------------------------------------------------------------
|
|
107
|
+
def Norm2(_X):
|
|
108
|
+
temp_vec = [x**2 for x in _X]
|
|
109
|
+
temp_sum = sum(temp_vec)
|
|
110
|
+
return math.sqrt(temp_sum)
|
|
111
|
+
|
|
112
|
+
# ------------------------------------------------------------------------------
|
|
113
|
+
def NormInf3D(_X):
|
|
114
|
+
temp_vec = [_X[3*i]**2 + _X[3*i+1]**2 + _X[3*i+2]**2 for i in range(int(len(_X)/3))]
|
|
115
|
+
max_squared_value = max(temp_vec)
|
|
116
|
+
return math.sqrt(max_squared_value)
|
|
117
|
+
|
|
118
|
+
# ------------------------------------------------------------------------------
|
|
119
|
+
def Dot(_X, _Y):
|
|
120
|
+
if len(_X) != len(_Y):
|
|
121
|
+
raise RuntimeError("custom_math::Dot: Dot product to be computed but _X and _Y do not have the same dimension!")
|
|
122
|
+
return sum( [_X[i]*_Y[i] for i in range(len(_X))] )
|
|
123
|
+
|
|
124
|
+
# ------------------------------------------------------------------------------
|
|
125
|
+
def Plus(_X, _Y):
|
|
126
|
+
if len(_X)!=len(_Y):
|
|
127
|
+
raise ValueError("custom_math::Plus: Wrong size of input variables!")
|
|
128
|
+
return [ _X[i]+_Y[i] for i in range(len(_X)) ]
|
|
129
|
+
|
|
130
|
+
# ------------------------------------------------------------------------------
|
|
131
|
+
def ScalarVectorProduct(scal, _X):
|
|
132
|
+
return [x*scal for x in _X]
|
|
133
|
+
|
|
134
|
+
# ------------------------------------------------------------------------------
|
|
135
|
+
def ScalarMatrixProduct(scal, _A):
|
|
136
|
+
return [ [ scal*_A[i][j] for j in range(RowSize(_A)) ] for i in range(CollSize(_A)) ]
|
|
137
|
+
|
|
138
|
+
# ------------------------------------------------------------------------------
|
|
139
|
+
def Prod(_A,_B):
|
|
140
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
141
|
+
_B = SafeConvertVectorToMatrix(_B)
|
|
142
|
+
|
|
143
|
+
row_size_A = RowSize(_A)
|
|
144
|
+
row_size_B = RowSize(_B)
|
|
145
|
+
coll_size_A = CollSize(_A)
|
|
146
|
+
coll_size_B = CollSize(_B)
|
|
147
|
+
|
|
148
|
+
if IsEmpty(_A) or IsEmpty(_B):
|
|
149
|
+
return []
|
|
150
|
+
if coll_size_A!=row_size_B:
|
|
151
|
+
raise ValueError("cusom_math::Prod: Product detected wrong size in the specified input array!")
|
|
152
|
+
|
|
153
|
+
result = [ [ sum(_A[k][i]*_B[j][k] for k in range(coll_size_A)) for i in range(row_size_A) ] for j in range(coll_size_B) ]
|
|
154
|
+
|
|
155
|
+
if CollSize(result) == 1:
|
|
156
|
+
return result[0]
|
|
157
|
+
else:
|
|
158
|
+
return result
|
|
159
|
+
|
|
160
|
+
# ------------------------------------------------------------------------------
|
|
161
|
+
def ElemwiseProd(_X,_Y):
|
|
162
|
+
if len(_X)!=len(_Y):
|
|
163
|
+
raise ValueError("custom_math::ElemwiseProd: Wrong size of input vectors!")
|
|
164
|
+
return [_X[i]*_Y[i] for i in range(len(_X))]
|
|
165
|
+
|
|
166
|
+
# ------------------------------------------------------------------------------
|
|
167
|
+
def Trans(_A):
|
|
168
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
169
|
+
|
|
170
|
+
if IsEmpty(_A):
|
|
171
|
+
return []
|
|
172
|
+
return list(map(list, zip(*_A)))
|
|
173
|
+
# ------------------------------------------------------------------------------
|
|
174
|
+
def Minus(_X,_Y):
|
|
175
|
+
return [ _X[i]-_Y[i] for i in range(len(_X))]
|
|
176
|
+
|
|
177
|
+
# ------------------------------------------------------------------------------
|
|
178
|
+
def TranslateToNewBasis(_A, basis):
|
|
179
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
180
|
+
|
|
181
|
+
if IsEmpty(_A):
|
|
182
|
+
return []
|
|
183
|
+
|
|
184
|
+
trans_basis = Trans(basis)
|
|
185
|
+
return Prod(trans_basis,_A)
|
|
186
|
+
|
|
187
|
+
# ------------------------------------------------------------------------------
|
|
188
|
+
def TranslateToOriginalBasis(_A, basis):
|
|
189
|
+
_A = SafeConvertVectorToMatrix(_A)
|
|
190
|
+
|
|
191
|
+
if IsEmpty(_A):
|
|
192
|
+
return []
|
|
193
|
+
|
|
194
|
+
return Prod(basis,_A)
|
|
195
|
+
|
|
196
|
+
# ------------------------------------------------------------------------------
|
|
197
|
+
def SolveLinearSystem(A,b):
|
|
198
|
+
A = Trans(A)
|
|
199
|
+
n = len(A)
|
|
200
|
+
for i in range(n):
|
|
201
|
+
A[i].append(b[i])
|
|
202
|
+
for i in range(0, n):
|
|
203
|
+
# Search for maximum in this column
|
|
204
|
+
maxEl = abs(A[i][i])
|
|
205
|
+
maxRow = i
|
|
206
|
+
for k in range(i+1, n):
|
|
207
|
+
if abs(A[k][i]) > maxEl:
|
|
208
|
+
maxEl = abs(A[k][i])
|
|
209
|
+
maxRow = k
|
|
210
|
+
|
|
211
|
+
# Swap maximum row with current row (column by column)
|
|
212
|
+
for k in range(i, n+1):
|
|
213
|
+
tmp = A[maxRow][k]
|
|
214
|
+
A[maxRow][k] = A[i][k]
|
|
215
|
+
A[i][k] = tmp
|
|
216
|
+
|
|
217
|
+
# Make all rows below this one 0 in current column
|
|
218
|
+
for k in range(i+1, n):
|
|
219
|
+
c = -A[k][i]/A[i][i]
|
|
220
|
+
for j in range(i, n+1):
|
|
221
|
+
if i == j:
|
|
222
|
+
A[k][j] = 0
|
|
223
|
+
else:
|
|
224
|
+
A[k][j] += c * A[i][j]
|
|
225
|
+
|
|
226
|
+
# Solve equation Ax=b for an upper triangular matrix A
|
|
227
|
+
x = [0 for i in range(n)]
|
|
228
|
+
for i in range(n-1, -1, -1):
|
|
229
|
+
x[i] = A[i][n]/A[i][i]
|
|
230
|
+
for k in range(i-1, -1, -1):
|
|
231
|
+
A[k][n] -= A[k][i] * x[i]
|
|
232
|
+
return x
|
|
233
|
+
|
|
234
|
+
# ------------------------------------------------------------------------------
|
|
235
|
+
# Interior point algorithm
|
|
236
|
+
# Nocedal & Wright, Numerical Optimization, 2nd edition, Algorithm 16.4, p.484, Springer
|
|
237
|
+
# Solves min x'*x with A*x<=b (x is of size n and A of size m*n)
|
|
238
|
+
# Note that original algorithm solves min x'*x with A*x>=b --> negation of input values in the beginning
|
|
239
|
+
def QuadProg(A, b, max_itr, tolerance):
|
|
240
|
+
m = RowSize(A)
|
|
241
|
+
n = CollSize(A)
|
|
242
|
+
|
|
243
|
+
A = ScalarMatrixProduct(-1.0,A)
|
|
244
|
+
b = ScalarVectorProduct(-1.0,b)
|
|
245
|
+
|
|
246
|
+
def rdrp(x,y,l,A,b):
|
|
247
|
+
temp_vec = Prod(Trans(A),l)
|
|
248
|
+
rd = Minus(x,temp_vec)
|
|
249
|
+
|
|
250
|
+
temp_vec = Prod(A,x)
|
|
251
|
+
rp = Minus(Minus(temp_vec,y),b)
|
|
252
|
+
return (rd,rp)
|
|
253
|
+
|
|
254
|
+
def GradResidu(y,l,A):
|
|
255
|
+
m = RowSize(A)
|
|
256
|
+
n = CollSize(A)
|
|
257
|
+
grad = [ZeroVector(n+2*m) for i in range(n+2*m)]
|
|
258
|
+
for i in range(n):
|
|
259
|
+
grad[i][i] = 1
|
|
260
|
+
for i in range(n):
|
|
261
|
+
for j in range(m):
|
|
262
|
+
grad[n+m+j][i] = -A[i][j]
|
|
263
|
+
for i in range(m):
|
|
264
|
+
for j in range(n):
|
|
265
|
+
grad[j][n+i] = A[j][i]
|
|
266
|
+
for i in range(m):
|
|
267
|
+
grad[n+i][n+i] = -1
|
|
268
|
+
for i in range(m):
|
|
269
|
+
grad[n+i][n+m+i] = l[i]
|
|
270
|
+
grad[n+m+i][n+m+i] = y[i]
|
|
271
|
+
return grad
|
|
272
|
+
|
|
273
|
+
#init
|
|
274
|
+
x = ZeroVector(n)
|
|
275
|
+
y = Ones(m) # slack variables
|
|
276
|
+
l = Ones(m) # lagrange multipliers
|
|
277
|
+
|
|
278
|
+
rd, rp = rdrp(x,y,l,A,b)
|
|
279
|
+
k = 0
|
|
280
|
+
error = 100000
|
|
281
|
+
while error>tolerance and k <= max_itr:
|
|
282
|
+
|
|
283
|
+
# solve affine delta
|
|
284
|
+
gradRes = GradResidu(y,l,A)
|
|
285
|
+
deltaXYLAff = ZeroVector(n+2*m)
|
|
286
|
+
rhs = ScalarVectorProduct(-1, VertCat(rd,VertCat(rp,ElemwiseProd(y,l))))
|
|
287
|
+
|
|
288
|
+
deltaXYLAff = SolveLinearSystem(gradRes,rhs)
|
|
289
|
+
|
|
290
|
+
# Drop and error if divergence is detected
|
|
291
|
+
if Norm2(deltaXYLAff)>1e20:
|
|
292
|
+
KM.Logger.PrintWarning("ShapeOpt::custom_math::quadprodg", "deltaXYLAff is NAN. The reason is, that feasible domain might be empty. This happens e.g. when the dJdX is parallel to dCdX (like at convergence with a single constraint)")
|
|
293
|
+
exit_code = 2
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
dxAff = deltaXYLAff[:n]
|
|
297
|
+
dyAff = deltaXYLAff[n:n+m]
|
|
298
|
+
dlAff = deltaXYLAff[n+m:]
|
|
299
|
+
|
|
300
|
+
mu = Dot(y,l)/m
|
|
301
|
+
alphaS = 1
|
|
302
|
+
alphaZ = 1
|
|
303
|
+
for i in range(m):
|
|
304
|
+
if dyAff[i]<0:
|
|
305
|
+
alphaS = min(alphaS, abs(y[i]/dyAff[i]))
|
|
306
|
+
if dlAff[i]<0:
|
|
307
|
+
alphaZ = min(alphaZ, abs(l[i]/dlAff[i]))
|
|
308
|
+
alphaAff = 0.8*min(alphaS,alphaZ)
|
|
309
|
+
|
|
310
|
+
muAff = Dot(Plus(y,ScalarVectorProduct(alphaAff,dyAff)),Plus(l,ScalarVectorProduct(alphaAff,dlAff))) / m
|
|
311
|
+
|
|
312
|
+
sigma = (muAff/mu)**3
|
|
313
|
+
|
|
314
|
+
# solve for delta
|
|
315
|
+
rhs = ScalarVectorProduct(-1, VertCat(rd,VertCat(rp, Plus( Plus(ElemwiseProd(y,l),ElemwiseProd(dyAff,dlAff)) , ScalarVectorProduct(-sigma*mu,Ones(m)) ))))
|
|
316
|
+
deltaXYL = SolveLinearSystem(gradRes,rhs)
|
|
317
|
+
|
|
318
|
+
dx = deltaXYL[:n]
|
|
319
|
+
dy = deltaXYL[n:n+m]
|
|
320
|
+
dl = deltaXYL[n+m:]
|
|
321
|
+
|
|
322
|
+
alphaS = 1
|
|
323
|
+
alphaZ = 1
|
|
324
|
+
for i in range(m):
|
|
325
|
+
if dy[i]<0:
|
|
326
|
+
alphaS = min(alphaS, abs(y[i]/dy[i]))
|
|
327
|
+
if dl[i]<0:
|
|
328
|
+
alphaZ = min(alphaZ, abs(l[i]/dl[i]))
|
|
329
|
+
alpha = 0.8*min(alphaS,alphaZ)
|
|
330
|
+
|
|
331
|
+
# apply delta
|
|
332
|
+
x = Plus(x,ScalarVectorProduct(alpha,dx))
|
|
333
|
+
y = Plus(y,ScalarVectorProduct(alpha,dy))
|
|
334
|
+
l = Plus(l,ScalarVectorProduct(alpha,dl))
|
|
335
|
+
rd,rp = rdrp(x,y,l,A,b)
|
|
336
|
+
k = k+1
|
|
337
|
+
|
|
338
|
+
# Determine current error
|
|
339
|
+
error = Norm2(VertCat(rd,rp))
|
|
340
|
+
|
|
341
|
+
if k==max_itr:
|
|
342
|
+
raise RuntimeError("custom_math::quadprodg: Suboptimization for projection to halfspaces did not converge in the specified number of iterations")
|
|
343
|
+
else:
|
|
344
|
+
# Exit code of 0 if convergence is reached
|
|
345
|
+
exit_code = 0
|
|
346
|
+
|
|
347
|
+
return x, k, error, exit_code
|
|
348
|
+
|
|
349
|
+
# ------------------------------------------------------------------------------
|
|
350
|
+
def PerformBisectioning(func, a, b, target, tolerance, max_itr):
|
|
351
|
+
|
|
352
|
+
fa_value_0, fa_is_converged = func(a)
|
|
353
|
+
fb_value_0, fb_is_converged = func(b)
|
|
354
|
+
|
|
355
|
+
error = None
|
|
356
|
+
itr = 0
|
|
357
|
+
|
|
358
|
+
# Always safe last argument for which function converges and return this if no solution is found
|
|
359
|
+
if fa_is_converged:
|
|
360
|
+
last_allowed_function_argument = a
|
|
361
|
+
elif fb_is_converged:
|
|
362
|
+
last_allowed_function_argument = b
|
|
363
|
+
|
|
364
|
+
# Check special cases
|
|
365
|
+
if abs(fa_value_0-target) < tolerance:
|
|
366
|
+
res_function_argument = a
|
|
367
|
+
error = abs(fa_value_0-target)
|
|
368
|
+
|
|
369
|
+
elif abs(fb_value_0-target) < tolerance:
|
|
370
|
+
res_function_argument = b
|
|
371
|
+
error = abs(fb_value_0-target)
|
|
372
|
+
|
|
373
|
+
elif abs(fa_value_0-fb_value_0) < 1e-13:
|
|
374
|
+
KM.Logger.PrintWarning("ShapeOpt::PerformBisectioning", "Bisectioning intervall yiels to identical function values!")
|
|
375
|
+
res_function_argument = a
|
|
376
|
+
error = abs(fb_value_0-target)
|
|
377
|
+
|
|
378
|
+
elif (fa_value_0-target)*(fb_value_0-target)>0:
|
|
379
|
+
KM.Logger.PrintWarning("ShapeOpt::PerformBisectioning", "Bisectioning on function, that has no root in specified intervall!! Returning the argument which yiels a closer value to the target.")
|
|
380
|
+
|
|
381
|
+
if abs(fa_value_0-target) < abs(fb_value_0-target):
|
|
382
|
+
res_function_argument = a
|
|
383
|
+
error = fa_value_0-target
|
|
384
|
+
else:
|
|
385
|
+
res_function_argument = b
|
|
386
|
+
error = fb_value_0-target
|
|
387
|
+
|
|
388
|
+
# Perform bisectioning if no special case applies
|
|
389
|
+
else:
|
|
390
|
+
p = (a + b)/2
|
|
391
|
+
|
|
392
|
+
for itr in range(1,max_itr+1):
|
|
393
|
+
fa_value, fa_is_converged = func(a)
|
|
394
|
+
fp_value, fp_is_converged = func(p)
|
|
395
|
+
|
|
396
|
+
if (fa_value-target)*(fp_value-target) < 0:
|
|
397
|
+
b = p
|
|
398
|
+
else:
|
|
399
|
+
a = p
|
|
400
|
+
|
|
401
|
+
p = (a + b)/2
|
|
402
|
+
|
|
403
|
+
fp_value, fp_is_converged = func(p)
|
|
404
|
+
error = abs(fp_value-target)
|
|
405
|
+
|
|
406
|
+
if fp_is_converged:
|
|
407
|
+
last_allowed_function_argument = p
|
|
408
|
+
|
|
409
|
+
if itr == max_itr:
|
|
410
|
+
res_function_argument = last_allowed_function_argument
|
|
411
|
+
KM.Logger.PrintWarning("ShapeOpt::PerformBisectioning", "Bisectioning did not converge in the specified maximum number of iterations!")
|
|
412
|
+
break
|
|
413
|
+
|
|
414
|
+
elif error < tolerance:
|
|
415
|
+
res_function_argument = p
|
|
416
|
+
break
|
|
417
|
+
|
|
418
|
+
return res_function_argument, itr, error
|
|
419
|
+
|
|
420
|
+
# --------------------------------------------------------------------------
|
|
421
|
+
def PerformGramSchmidtOrthogonalization(vector_space):
|
|
422
|
+
V = vector_space
|
|
423
|
+
B = []
|
|
424
|
+
|
|
425
|
+
# Orthogonalization
|
|
426
|
+
norm2_V0 = Norm2(V[0])
|
|
427
|
+
B.append( ScalarVectorProduct(1/norm2_V0,V[0]) )
|
|
428
|
+
for v in V[1:]:
|
|
429
|
+
for b in B:
|
|
430
|
+
norm2_b = Norm2(b)
|
|
431
|
+
v = Minus( v , ScalarVectorProduct( Dot(v,b)/norm2_b**2 , b ) )
|
|
432
|
+
|
|
433
|
+
# Add only if vector is independent
|
|
434
|
+
norm2_v = Norm2(v)
|
|
435
|
+
if norm2_v>1e-10:
|
|
436
|
+
B.append( ScalarVectorProduct(1/norm2_v,v) )
|
|
437
|
+
else:
|
|
438
|
+
KM.Logger.PrintWarning("ShapeOpt::PerformGramSchmidtOrthogonalization", "Zero basis vector after Gram-Schmidt orthogonalization!")
|
|
439
|
+
B.append(v)
|
|
440
|
+
|
|
441
|
+
return B
|
|
442
|
+
|
|
443
|
+
# ==============================================================================
|