KratosOptimizationApplication 10.4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- KratosMultiphysics/.libs/KratosOptimizationApplication.so +0 -0
- KratosMultiphysics/.libs/libKratosOptimizationCore.dylib +0 -0
- KratosMultiphysics/OptimizationApplication/__init__.py +19 -0
- KratosMultiphysics/OptimizationApplication/algorithms/NLOPT_algorithms.py +255 -0
- KratosMultiphysics/OptimizationApplication/algorithms/SciPy_algorithms.py +154 -0
- KratosMultiphysics/OptimizationApplication/algorithms/__init__.py +0 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm.py +78 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_adam.py +68 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_base.py +393 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_gradient_projection.py +355 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_momentum_relaxed_gradient_projection.py +70 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_nesterov_accelarated_gradient.py +60 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_relaxed_gradient_projection.py +263 -0
- KratosMultiphysics/OptimizationApplication/algorithms/algorithm_steepest_descent.py +205 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_constraint.py +194 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_NLOPT_objective.py +191 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_constraint.py +123 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_SciPy_objective.py +148 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_constraint.py +180 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_objective.py +133 -0
- KratosMultiphysics/OptimizationApplication/algorithms/standardized_rgp_constraint.py +268 -0
- KratosMultiphysics/OptimizationApplication/analyses_controller.py +75 -0
- KratosMultiphysics/OptimizationApplication/controls/control.py +123 -0
- KratosMultiphysics/OptimizationApplication/controls/external_response_function_control.py +149 -0
- KratosMultiphysics/OptimizationApplication/controls/master_control.py +198 -0
- KratosMultiphysics/OptimizationApplication/controls/material/material_properties_control.py +115 -0
- KratosMultiphysics/OptimizationApplication/controls/material/simp_control.py +229 -0
- KratosMultiphysics/OptimizationApplication/controls/shape/vertex_morphing_shape_control.py +289 -0
- KratosMultiphysics/OptimizationApplication/controls/thickness/shell_thickness_control.py +180 -0
- KratosMultiphysics/OptimizationApplication/controls_controller.py +205 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/avg_abs_improvement_conv_criterion.py +98 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/combined_conv_criterion.py +87 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/constraint_conv_criterion.py +68 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/convergence_criterion.py +26 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/l2_conv_criterion.py +77 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/magnitude_reduction_conv_criterion.py +85 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/max_iter_conv_criterion.py +48 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/patience_conv_criterion.py +116 -0
- KratosMultiphysics/OptimizationApplication/convergence_criteria/target_value_conv_criterion.py +64 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy.py +46 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/execution_policy_decorator.py +67 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/independent_analysis_execution_policy.py +78 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/kratos_analysis_execution_policy.py +137 -0
- KratosMultiphysics/OptimizationApplication/execution_policies/stepping_analysis_execution_policy.py +88 -0
- KratosMultiphysics/OptimizationApplication/filtering/explicit_filter.py +124 -0
- KratosMultiphysics/OptimizationApplication/filtering/filter.py +188 -0
- KratosMultiphysics/OptimizationApplication/filtering/filter_utils.py +55 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_analysis.py +139 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_scalar_solver.py +39 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_shape_solver.py +67 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_solver_base.py +275 -0
- KratosMultiphysics/OptimizationApplication/filtering/helmholtz_vector_solver.py +39 -0
- KratosMultiphysics/OptimizationApplication/filtering/implicit_filter.py +192 -0
- KratosMultiphysics/OptimizationApplication/filtering/python_solvers_wrapper_implicit_filters.py +56 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/connectivity_preserving_model_part_controller.py +72 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/external_response_function_model_part_controller.py +110 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/mdpa_model_part_controller.py +44 -0
- KratosMultiphysics/OptimizationApplication/model_part_controllers/model_part_controller.py +19 -0
- KratosMultiphysics/OptimizationApplication/model_parts_controller.py +92 -0
- KratosMultiphysics/OptimizationApplication/optimization_analysis.py +146 -0
- KratosMultiphysics/OptimizationApplication/optimizations_controller.py +223 -0
- KratosMultiphysics/OptimizationApplication/optimizer.py +61 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_ascii_output_process.py +212 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_field_output_process.py +122 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_graph_output_process.py +184 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_hdf5_output_process.py +84 -0
- KratosMultiphysics/OptimizationApplication/processes/optimization_problem_vtu_output_process.py +94 -0
- KratosMultiphysics/OptimizationApplication/processes/spatial_statistics_computation_process.py +81 -0
- KratosMultiphysics/OptimizationApplication/responses/__init__.py +0 -0
- KratosMultiphysics/OptimizationApplication/responses/additive_manufacturing_responses.py +410 -0
- KratosMultiphysics/OptimizationApplication/responses/analysis_based_response_function_factory.py +14 -0
- KratosMultiphysics/OptimizationApplication/responses/analysis_free_response_function_factory.py +14 -0
- KratosMultiphysics/OptimizationApplication/responses/base_response.py +66 -0
- KratosMultiphysics/OptimizationApplication/responses/binary_operator_response_function.py +103 -0
- KratosMultiphysics/OptimizationApplication/responses/combined_response_function.py +127 -0
- KratosMultiphysics/OptimizationApplication/responses/discrete_value_residual_response_function.py +131 -0
- KratosMultiphysics/OptimizationApplication/responses/evaluation_response_function.py +68 -0
- KratosMultiphysics/OptimizationApplication/responses/external_response_function.py +87 -0
- KratosMultiphysics/OptimizationApplication/responses/geometric_centroid_deviation_response_function.py +97 -0
- KratosMultiphysics/OptimizationApplication/responses/linear_strain_energy_response_function.py +72 -0
- KratosMultiphysics/OptimizationApplication/responses/literal_value_response_function.py +33 -0
- KratosMultiphysics/OptimizationApplication/responses/log_response_function.py +47 -0
- KratosMultiphysics/OptimizationApplication/responses/mass_response_function.py +71 -0
- KratosMultiphysics/OptimizationApplication/responses/response_function.py +126 -0
- KratosMultiphysics/OptimizationApplication/responses/response_routine.py +158 -0
- KratosMultiphysics/OptimizationApplication/responses/structural_responses.py +335 -0
- KratosMultiphysics/OptimizationApplication/responses_controller.py +390 -0
- KratosMultiphysics/OptimizationApplication/utilities/buffered_dict.py +399 -0
- KratosMultiphysics/OptimizationApplication/utilities/component_data_view.py +74 -0
- KratosMultiphysics/OptimizationApplication/utilities/helper_utilities.py +40 -0
- KratosMultiphysics/OptimizationApplication/utilities/logger_utilities.py +222 -0
- KratosMultiphysics/OptimizationApplication/utilities/model_part_utilities.py +117 -0
- KratosMultiphysics/OptimizationApplication/utilities/opt_line_search.py +173 -0
- KratosMultiphysics/OptimizationApplication/utilities/opt_projection.py +191 -0
- KratosMultiphysics/OptimizationApplication/utilities/optimization_problem.py +237 -0
- KratosMultiphysics/OptimizationApplication/utilities/optimization_problem_utilities.py +237 -0
- KratosMultiphysics/OptimizationApplication/utilities/response_utilities.py +249 -0
- KratosMultiphysics/OptimizationApplication/utilities/timer.py +45 -0
- KratosMultiphysics/OptimizationApplication/utilities/union_utilities.py +6 -0
- kratosoptimizationapplication-10.4.4.dist-info/METADATA +25 -0
- kratosoptimizationapplication-10.4.4.dist-info/RECORD +106 -0
- kratosoptimizationapplication-10.4.4.dist-info/WHEEL +6 -0
- kratosoptimizationapplication.dylibs/libKratosCore.dylib +4 -0
- kratosoptimizationapplication.dylibs/libgcc_s.1.1.dylib +0 -0
- kratosoptimizationapplication.dylibs/libgomp.1.dylib +0 -0
- kratosoptimizationapplication.dylibs/libstdc++.6.dylib +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
class ConvergenceCriterion(abc.ABC):
|
|
5
|
+
"""Initializes the convergence criteria
|
|
6
|
+
"""
|
|
7
|
+
@abc.abstractmethod
|
|
8
|
+
def Initialize(self) -> None:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
"""This method returns whether the convergence criteria detected the optimization
|
|
12
|
+
has converged.
|
|
13
|
+
"""
|
|
14
|
+
@abc.abstractmethod
|
|
15
|
+
def IsConverged(self) -> bool:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
"""Finalizes the convergence criteria """
|
|
19
|
+
@abc.abstractmethod
|
|
20
|
+
def Finalize(self) -> None:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
"""Returns a list[(str, Any)] with information about the current convergence."""
|
|
24
|
+
@abc.abstractmethod
|
|
25
|
+
def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
|
|
26
|
+
pass
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import typing, numpy
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
import KratosMultiphysics.OptimizationApplication as KratosOA
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentValueByFullName
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
|
|
9
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
10
|
+
|
|
11
|
+
def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
|
|
12
|
+
if not parameters.Has("settings"):
|
|
13
|
+
raise RuntimeError(f"L2ConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
14
|
+
return L2ConvCriterion(parameters["settings"], optimization_problem)
|
|
15
|
+
|
|
16
|
+
class L2ConvCriterion(ConvergenceCriterion):
|
|
17
|
+
"""
|
|
18
|
+
L2ConvCriterion is a convergence criterion based on the L2 norm of a specified field in an optimization problem.
|
|
19
|
+
|
|
20
|
+
This class checks whether the L2 norm of a given field (e.g., search direction) falls below a specified tolerance,
|
|
21
|
+
indicating convergence. The field can be either historical or non-historical, and the criterion is configurable
|
|
22
|
+
via parameters.
|
|
23
|
+
"""
|
|
24
|
+
@classmethod
|
|
25
|
+
def GetDefaultParameters(cls):
|
|
26
|
+
return Kratos.Parameters("""{
|
|
27
|
+
"component_name": "algorithm",
|
|
28
|
+
"field_name" : "search_direction:historical",
|
|
29
|
+
"tolerance" : 1e-9
|
|
30
|
+
}""")
|
|
31
|
+
|
|
32
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
33
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
34
|
+
|
|
35
|
+
self.__component_name = parameters["component_name"].GetString()
|
|
36
|
+
self.__field_name = parameters["field_name"].GetString()
|
|
37
|
+
self.__tolerance = parameters["tolerance"].GetDouble()
|
|
38
|
+
self.__optimization_problem = optimization_problem
|
|
39
|
+
self.__component_data_view: 'typing.Optional[ComponentDataView]' = None
|
|
40
|
+
|
|
41
|
+
if self.__field_name.find(":") == -1:
|
|
42
|
+
# not found where the data location. So the default for field names
|
|
43
|
+
# will be unbuffered (i.e. non_historical). So appending it
|
|
44
|
+
self.__field_name += ":non_historical"
|
|
45
|
+
|
|
46
|
+
if self.__tolerance < 0.0:
|
|
47
|
+
raise RuntimeError(f"Tolerance should be non-negative [ tolerance = {self.__tolerance} ].")
|
|
48
|
+
|
|
49
|
+
def Initialize(self):
|
|
50
|
+
component = GetComponentHavingDataByFullName(self.__component_name, self.__optimization_problem)
|
|
51
|
+
self.__component_data_view = ComponentDataView(component, self.__optimization_problem)
|
|
52
|
+
|
|
53
|
+
@time_decorator()
|
|
54
|
+
def IsConverged(self) -> bool:
|
|
55
|
+
field: Kratos.TensorAdaptors.DoubleTensorAdaptor = GetComponentValueByFullName(self.__component_data_view, self.__field_name)
|
|
56
|
+
|
|
57
|
+
if not hasattr(field, "data"):
|
|
58
|
+
raise RuntimeError(f"The value represented by {self.__field_name} is not a field.")
|
|
59
|
+
|
|
60
|
+
self.__norm = numpy.linalg.norm(field.data)
|
|
61
|
+
self.__conv = self.__norm <= self.__tolerance
|
|
62
|
+
self.__component_data_view.GetBufferedData().SetValue(self.__field_name.split(':')[0] + "_l2_norm", self.__norm)
|
|
63
|
+
return self.__conv
|
|
64
|
+
|
|
65
|
+
def Finalize(self):
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
|
|
69
|
+
info = [
|
|
70
|
+
('type' , 'l2_conv_criterion'),
|
|
71
|
+
('l2_norm' , self.__norm),
|
|
72
|
+
('tolerance' , self.__tolerance),
|
|
73
|
+
('component_name', self.__component_name),
|
|
74
|
+
('field_name' , self.__field_name),
|
|
75
|
+
('status' , str("converged" if self.__conv else "not converged"))
|
|
76
|
+
]
|
|
77
|
+
return info
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentValueByFullName
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
9
|
+
|
|
10
|
+
def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
|
|
11
|
+
if not parameters.Has("settings"):
|
|
12
|
+
raise RuntimeError(f"MagnitudeReductionConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
13
|
+
return MagnitudeReductionConvCriterion(parameters["settings"], optimization_problem)
|
|
14
|
+
|
|
15
|
+
class MagnitudeReductionConvCriterion(ConvergenceCriterion):
|
|
16
|
+
"""
|
|
17
|
+
Convergence criterion based on the reduction of a magnitude (e.g., objective value) during optimization.
|
|
18
|
+
|
|
19
|
+
This criterion checks whether the current value of a specified component has been reduced below a target value,
|
|
20
|
+
which is computed as a scaling factor of the initial value or a specified machine precision, whichever is greater.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
RuntimeError: If the target scaling factor is not greater than zero or machine precision is negative.
|
|
24
|
+
"""
|
|
25
|
+
@classmethod
|
|
26
|
+
def GetDefaultParameters(cls):
|
|
27
|
+
return Kratos.Parameters("""{
|
|
28
|
+
"component_name" : "algorithm",
|
|
29
|
+
"value_name" : "std_obj_value",
|
|
30
|
+
"target_scaling_factor": 1e-3,
|
|
31
|
+
"machine_precision" : 1e-16
|
|
32
|
+
}""")
|
|
33
|
+
|
|
34
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
35
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
36
|
+
|
|
37
|
+
self.__component_name = parameters["component_name"].GetString()
|
|
38
|
+
self.__value_name = parameters["value_name"].GetString()
|
|
39
|
+
self.__target_scaling_factor = parameters["target_scaling_factor"].GetDouble()
|
|
40
|
+
self.__machine_precision = parameters["machine_precision"].GetDouble()
|
|
41
|
+
self.__optimization_problem = optimization_problem
|
|
42
|
+
self.__component_data_view: 'typing.Optional[ComponentDataView]' = None
|
|
43
|
+
|
|
44
|
+
if self.__value_name.find(":") == -1:
|
|
45
|
+
# not found where the data location. So the default for value names
|
|
46
|
+
# will be buffered (i.e. historical). So appending it
|
|
47
|
+
self.__value_name += ":historical"
|
|
48
|
+
|
|
49
|
+
if self.__target_scaling_factor <= 0.0:
|
|
50
|
+
raise RuntimeError(f"The target scaling factor should be greater than zero [ target_scaling_factor = {self.__target_scaling_factor} ].")
|
|
51
|
+
|
|
52
|
+
if self.__machine_precision < 0.0:
|
|
53
|
+
raise RuntimeError(f"The machine precision should be non-negative [ machine_precision = {self.__machine_precision} ].")
|
|
54
|
+
|
|
55
|
+
def Initialize(self):
|
|
56
|
+
component = GetComponentHavingDataByFullName(self.__component_name, self.__optimization_problem)
|
|
57
|
+
self.__component_data_view = ComponentDataView(component, self.__optimization_problem)
|
|
58
|
+
|
|
59
|
+
@time_decorator()
|
|
60
|
+
def IsConverged(self) -> bool:
|
|
61
|
+
iter = self.__optimization_problem.GetStep()
|
|
62
|
+
self.__current_value = GetComponentValueByFullName(self.__component_data_view, self.__value_name)
|
|
63
|
+
|
|
64
|
+
if iter == 0:
|
|
65
|
+
self.__target_value = max(self.__current_value * self.__target_scaling_factor, self.__machine_precision)
|
|
66
|
+
self.__component_data_view.GetUnBufferedData().SetValue(f"{self.__value_name.split(':')[0]}_conv_target", self.__target_value)
|
|
67
|
+
self.__conv = False
|
|
68
|
+
else:
|
|
69
|
+
self.__conv = self.__current_value <= self.__target_value
|
|
70
|
+
|
|
71
|
+
return self.__conv
|
|
72
|
+
|
|
73
|
+
def Finalize(self):
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
|
|
77
|
+
info = [
|
|
78
|
+
('type' , 'magnitude_reduction_conv_criterion'),
|
|
79
|
+
('value' , self.__current_value),
|
|
80
|
+
('target_value' , self.__target_value),
|
|
81
|
+
('component_name', self.__component_name),
|
|
82
|
+
('value_name' , self.__value_name),
|
|
83
|
+
('status' , str("converged" if self.__conv else "not converged"))
|
|
84
|
+
]
|
|
85
|
+
return info
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
6
|
+
|
|
7
|
+
def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
|
|
8
|
+
if not parameters.Has("settings"):
|
|
9
|
+
raise RuntimeError(f"MaxIterConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
10
|
+
return MaxIterConvCriterion(parameters["settings"], optimization_problem)
|
|
11
|
+
|
|
12
|
+
class MaxIterConvCriterion(ConvergenceCriterion):
|
|
13
|
+
"""
|
|
14
|
+
MaxIterConvCriterion is a convergence criterion for optimization problems based on the maximum number of iterations.
|
|
15
|
+
"""
|
|
16
|
+
@classmethod
|
|
17
|
+
def GetDefaultParameters(cls):
|
|
18
|
+
return Kratos.Parameters("""{
|
|
19
|
+
"max_iter": 0
|
|
20
|
+
}""")
|
|
21
|
+
|
|
22
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
23
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
24
|
+
|
|
25
|
+
self.__max_iter = parameters["max_iter"].GetInt()
|
|
26
|
+
self.__optimization_problem = optimization_problem
|
|
27
|
+
|
|
28
|
+
if self.__max_iter < 0:
|
|
29
|
+
raise RuntimeError(f"The number of max iterations cannot negative.")
|
|
30
|
+
|
|
31
|
+
def Initialize(self):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@time_decorator()
|
|
35
|
+
def IsConverged(self) -> bool:
|
|
36
|
+
self.__conv = (self.__optimization_problem.GetStep() >= self.__max_iter)
|
|
37
|
+
return self.__conv
|
|
38
|
+
|
|
39
|
+
def Finalize(self):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
|
|
43
|
+
info = [
|
|
44
|
+
("type" , "max_iter_conv_criterion"),
|
|
45
|
+
("iter" , f"{self.__optimization_problem.GetStep()} of {self.__max_iter}"),
|
|
46
|
+
("status", str("converged" if self.__conv else "not converged"))
|
|
47
|
+
]
|
|
48
|
+
return info
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import numpy
|
|
3
|
+
import KratosMultiphysics as Kratos
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentValueByFullName
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
|
|
9
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
10
|
+
|
|
11
|
+
def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
|
|
12
|
+
if not parameters.Has("settings"):
|
|
13
|
+
raise RuntimeError(f"PatienceConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
14
|
+
return PatienceConvCriterion(parameters["settings"], optimization_problem)
|
|
15
|
+
|
|
16
|
+
class PatienceConvCriterion(ConvergenceCriterion):
|
|
17
|
+
"""
|
|
18
|
+
Convergence criterion based on the 'patience' concept, commonly used in optimization and machine learning.
|
|
19
|
+
|
|
20
|
+
This criterion monitors the improvement of a specified value (e.g., objective function) over iterations.
|
|
21
|
+
Convergence is declared if no significant improvement (greater than a specified tolerance) is observed
|
|
22
|
+
for a consecutive number of iterations (patience_itr), after a minimum number of iterations (minimum_itr)
|
|
23
|
+
have been performed.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
RuntimeError: If tolerance is negative, minimum_itr is not positive, patience_itr is not greater than minimum_itr,
|
|
27
|
+
or the monitored value is not a float or int.
|
|
28
|
+
"""
|
|
29
|
+
@classmethod
|
|
30
|
+
def GetDefaultParameters(cls):
|
|
31
|
+
return Kratos.Parameters("""{
|
|
32
|
+
"component_name": "algorithm",
|
|
33
|
+
"value_name" : "std_obj_value",
|
|
34
|
+
"minimum_itr" : 100,
|
|
35
|
+
"patience_itr" : 50,
|
|
36
|
+
"tolerance" : 1e-6
|
|
37
|
+
}""")
|
|
38
|
+
|
|
39
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
40
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
41
|
+
|
|
42
|
+
self.__component_name = parameters["component_name"].GetString()
|
|
43
|
+
self.__value_name = parameters["value_name"].GetString()
|
|
44
|
+
self.__tolerance = parameters["tolerance"].GetDouble()
|
|
45
|
+
self.__patience_itr = parameters["patience_itr"].GetInt()
|
|
46
|
+
self.__minimum_itr = parameters["minimum_itr"].GetInt()
|
|
47
|
+
self.__optimization_problem = optimization_problem
|
|
48
|
+
self.__component_data_view: 'typing.Optional[ComponentDataView]' = None
|
|
49
|
+
|
|
50
|
+
if self.__value_name.find(":") == -1:
|
|
51
|
+
# not found where the data location. So the default for value names
|
|
52
|
+
# will be buffered (i.e. historical). So appending it
|
|
53
|
+
self.__value_name += ":historical"
|
|
54
|
+
|
|
55
|
+
if self.__tolerance < 0.0:
|
|
56
|
+
raise RuntimeError(f"Tolerance should be non-negative [ tolerance = {self.__tolerance} ].")
|
|
57
|
+
|
|
58
|
+
if self.__minimum_itr <= 0:
|
|
59
|
+
raise RuntimeError(f"The minimum number of iterations needs to be greater than 0 [ minimum_itr = {self.__minimum_itr} ].")
|
|
60
|
+
|
|
61
|
+
if self.__patience_itr >= self.__minimum_itr:
|
|
62
|
+
raise RuntimeError(f"The number of patience iterations needs to be greater than minimum number of iterations [ patience_itr = {self.__patience_itr}, minimum_itr = {self.__minimum_itr} ].")
|
|
63
|
+
|
|
64
|
+
self.__best_value: 'typing.Optional[float]' = None
|
|
65
|
+
self.__patience_step = 0
|
|
66
|
+
|
|
67
|
+
def Initialize(self):
|
|
68
|
+
component = GetComponentHavingDataByFullName(self.__component_name, self.__optimization_problem)
|
|
69
|
+
self.__component_data_view = ComponentDataView(component, self.__optimization_problem)
|
|
70
|
+
|
|
71
|
+
@time_decorator()
|
|
72
|
+
def IsConverged(self) -> bool:
|
|
73
|
+
step = self.__optimization_problem.GetStep()
|
|
74
|
+
value = GetComponentValueByFullName(self.__component_data_view, self.__value_name)
|
|
75
|
+
|
|
76
|
+
if not isinstance(value, float) and not isinstance(value, int):
|
|
77
|
+
raise RuntimeError(f"The value represented by {self.__value_name} is not a floating or int value.")
|
|
78
|
+
|
|
79
|
+
if self.__best_value is None:
|
|
80
|
+
self.__init_value = value
|
|
81
|
+
self.__best_value = value
|
|
82
|
+
|
|
83
|
+
if step >= self.__minimum_itr:
|
|
84
|
+
if self.__best_value > value + self.__tolerance * self.__init_value:
|
|
85
|
+
self.__best_value = value
|
|
86
|
+
self.__patience_step = 0
|
|
87
|
+
else:
|
|
88
|
+
self.__patience_step += 1
|
|
89
|
+
|
|
90
|
+
# say it is converged if you cannot find a better solution within the number of
|
|
91
|
+
# patience iterations. That means, there were no improvement for patience iterations.
|
|
92
|
+
self.__conv = self.__patience_step >= self.__patience_itr
|
|
93
|
+
else:
|
|
94
|
+
self.__conv = False
|
|
95
|
+
|
|
96
|
+
self.__component_data_view.GetBufferedData().SetValue(f"{self.__value_name.split(':')[0]}_pat_itr_{self.__patience_itr}_best_value", self.__best_value)
|
|
97
|
+
self.__component_data_view.GetBufferedData().SetValue(f"{self.__value_name.split(':')[0]}_pat_itr_{self.__patience_itr}_patience_step", self.__patience_step)
|
|
98
|
+
|
|
99
|
+
return self.__conv
|
|
100
|
+
|
|
101
|
+
def Finalize(self):
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
|
|
105
|
+
info = [
|
|
106
|
+
('type' , 'patience_conv_criterion'),
|
|
107
|
+
('best_value' , self.__best_value),
|
|
108
|
+
('patience_step' , self.__patience_step),
|
|
109
|
+
('patience_itr' , self.__patience_itr),
|
|
110
|
+
('minimum_itr' , self.__minimum_itr),
|
|
111
|
+
('tolerance' , self.__tolerance),
|
|
112
|
+
('component_name', self.__component_name),
|
|
113
|
+
('value_name' , self.__value_name),
|
|
114
|
+
('status' , str("converged" if self.__conv else "not converged"))
|
|
115
|
+
]
|
|
116
|
+
return info
|
KratosMultiphysics/OptimizationApplication/convergence_criteria/target_value_conv_criterion.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentValueByFullName
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator
|
|
9
|
+
|
|
10
|
+
def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ConvergenceCriterion:
|
|
11
|
+
if not parameters.Has("settings"):
|
|
12
|
+
raise RuntimeError(f"TargetValueConvCriterion instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
13
|
+
return TargetValueConvCriterion(parameters["settings"], optimization_problem)
|
|
14
|
+
|
|
15
|
+
class TargetValueConvCriterion(ConvergenceCriterion):
|
|
16
|
+
"""
|
|
17
|
+
TargetValueConvCriterion is a convergence criterion for optimization problems that checks
|
|
18
|
+
whether a specified value associated with a component has reached a target threshold.
|
|
19
|
+
"""
|
|
20
|
+
@classmethod
|
|
21
|
+
def GetDefaultParameters(cls):
|
|
22
|
+
return Kratos.Parameters("""{
|
|
23
|
+
"component_name": "algorithm",
|
|
24
|
+
"value_name" : "std_obj_value",
|
|
25
|
+
"target_value" : 1e-9
|
|
26
|
+
}""")
|
|
27
|
+
|
|
28
|
+
def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
29
|
+
parameters.ValidateAndAssignDefaults(self.GetDefaultParameters())
|
|
30
|
+
|
|
31
|
+
self.__component_name = parameters["component_name"].GetString()
|
|
32
|
+
self.__value_name = parameters["value_name"].GetString()
|
|
33
|
+
self.__target_value = parameters["target_value"].GetDouble()
|
|
34
|
+
self.__optimization_problem = optimization_problem
|
|
35
|
+
self.__component_data_view: 'typing.Optional[ComponentDataView]' = None
|
|
36
|
+
|
|
37
|
+
if self.__value_name.find(":") == -1:
|
|
38
|
+
# not found where the data location. So the default for value names
|
|
39
|
+
# will be buffered (i.e. historical). So appending it
|
|
40
|
+
self.__value_name += ":historical"
|
|
41
|
+
|
|
42
|
+
def Initialize(self):
|
|
43
|
+
component = GetComponentHavingDataByFullName(self.__component_name, self.__optimization_problem)
|
|
44
|
+
self.__component_data_view = ComponentDataView(component, self.__optimization_problem)
|
|
45
|
+
|
|
46
|
+
@time_decorator()
|
|
47
|
+
def IsConverged(self) -> bool:
|
|
48
|
+
self.__current_value = GetComponentValueByFullName(self.__component_data_view, self.__value_name)
|
|
49
|
+
self.__conv = self.__current_value <= self.__target_value
|
|
50
|
+
return self.__conv
|
|
51
|
+
|
|
52
|
+
def Finalize(self):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def GetInfo(self) -> 'list[tuple[str, typing.Union[int, float, str]]]':
|
|
56
|
+
info = [
|
|
57
|
+
('type' , 'target_value_conv_criteria'),
|
|
58
|
+
('value' , self.__current_value),
|
|
59
|
+
('target_value' , self.__target_value),
|
|
60
|
+
('component_name', self.__component_name),
|
|
61
|
+
('value_name' , self.__value_name),
|
|
62
|
+
('status' , str("converged" if self.__conv else "not converged"))
|
|
63
|
+
]
|
|
64
|
+
return info
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
import KratosMultiphysics as Kratos
|
|
3
|
+
|
|
4
|
+
class ExecutionPolicy(ABC):
|
|
5
|
+
"""Base class for execution policy
|
|
6
|
+
|
|
7
|
+
This represents the base class for the execution policy which
|
|
8
|
+
can be used to execute primal analysis to obtain response function
|
|
9
|
+
values and their gradients.
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self, execution_policy_name: str) -> None:
|
|
13
|
+
self.__name = execution_policy_name
|
|
14
|
+
|
|
15
|
+
def GetName(self) -> str:
|
|
16
|
+
return self.__name
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def Initialize(self) -> None:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def Check(self) -> None:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def Finalize(self) -> None:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def GetAnalysisModelPart(self) -> Kratos.ModelPart:
|
|
32
|
+
"""Returns the analysis model part.
|
|
33
|
+
|
|
34
|
+
Each execution policy will be using a domain to compute the primal model part.
|
|
35
|
+
This method should return that domain as a Kratos::ModelPart.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Kratos.ModelPart: Domain used to compute the primal solution.
|
|
39
|
+
"""
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def Execute(self) -> None:
|
|
44
|
+
"""Solves the associated primal problem.
|
|
45
|
+
"""
|
|
46
|
+
pass
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import KratosMultiphysics as Kratos
|
|
2
|
+
from KratosMultiphysics.model_parameters_factory import KratosModelParametersFactory
|
|
3
|
+
from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy
|
|
4
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import FileLogger
|
|
5
|
+
from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger
|
|
6
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OptimizationComponentFactory
|
|
7
|
+
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll
|
|
9
|
+
|
|
10
|
+
class ExecutionPolicyDecorator(ExecutionPolicy):
|
|
11
|
+
def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
|
|
12
|
+
default_parameters = Kratos.Parameters("""{
|
|
13
|
+
"name" : "",
|
|
14
|
+
"type" : "please_provide_python_module_name",
|
|
15
|
+
"module" : "KratosMultiphysics.OptimizationApplication.execution_policies",
|
|
16
|
+
"pre_operations" : [],
|
|
17
|
+
"post_operations": [],
|
|
18
|
+
"log_in_file" : false,
|
|
19
|
+
"log_file_name" : "",
|
|
20
|
+
"settings" : {}
|
|
21
|
+
}""")
|
|
22
|
+
parameters.ValidateAndAssignDefaults(default_parameters)
|
|
23
|
+
|
|
24
|
+
super().__init__(parameters["name"].GetString())
|
|
25
|
+
|
|
26
|
+
self.__log_file_name = parameters["log_file_name"].GetString()
|
|
27
|
+
self.__log_in_file = parameters["log_in_file"].GetBool()
|
|
28
|
+
|
|
29
|
+
if self.__log_in_file and self.__log_file_name == "":
|
|
30
|
+
raise RuntimeError("Logger file name is empty for execution policy. Please provide \"log_file_name\" or make \"log_in_file\" to false.")
|
|
31
|
+
|
|
32
|
+
factory = KratosModelParametersFactory(model)
|
|
33
|
+
|
|
34
|
+
# create operations
|
|
35
|
+
self.__list_of_pre_operations: 'list[Kratos.Operation]' = factory.ConstructListOfItems(parameters["pre_operations"])
|
|
36
|
+
self.__list_of_post_operations: 'list[Kratos.Operation]' = factory.ConstructListOfItems(parameters["post_operations"])
|
|
37
|
+
|
|
38
|
+
# create execution policy
|
|
39
|
+
self.__execution_policy: ExecutionPolicy = OptimizationComponentFactory(model, parameters, optimization_problem)
|
|
40
|
+
|
|
41
|
+
def GetExecutionPolicy(self):
|
|
42
|
+
return self.__execution_policy
|
|
43
|
+
|
|
44
|
+
def GetAnalysisModelPart(self) -> Kratos.ModelPart:
|
|
45
|
+
return self.__execution_policy.GetAnalysisModelPart()
|
|
46
|
+
|
|
47
|
+
def Initialize(self):
|
|
48
|
+
self.__execution_policy.Initialize()
|
|
49
|
+
|
|
50
|
+
def Check(self):
|
|
51
|
+
self.__execution_policy.Check()
|
|
52
|
+
|
|
53
|
+
def Finalize(self):
|
|
54
|
+
self.__execution_policy.Finalize()
|
|
55
|
+
|
|
56
|
+
def Execute(self):
|
|
57
|
+
with TimeLogger(f"ExecutionPolicyDecorator::Executing {self.GetName()}", None, "Finished"):
|
|
58
|
+
if self.__log_in_file:
|
|
59
|
+
with FileLogger(self.__log_file_name):
|
|
60
|
+
self.__ExecuteWithoutFileLogger()
|
|
61
|
+
else:
|
|
62
|
+
self.__ExecuteWithoutFileLogger()
|
|
63
|
+
|
|
64
|
+
def __ExecuteWithoutFileLogger(self):
|
|
65
|
+
CallOnAll(self.__list_of_pre_operations, Kratos.Operation.Execute)
|
|
66
|
+
self.__execution_policy.Execute()
|
|
67
|
+
CallOnAll(self.__list_of_post_operations, Kratos.Operation.Execute)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from importlib import import_module
|
|
3
|
+
|
|
4
|
+
import KratosMultiphysics as Kratos
|
|
5
|
+
from KratosMultiphysics.analysis_stage import AnalysisStage
|
|
6
|
+
from KratosMultiphysics.project import Project
|
|
7
|
+
from KratosMultiphysics.orchestrators.orchestrator import Orchestrator
|
|
8
|
+
from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy
|
|
9
|
+
from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetClassModuleFromKratos
|
|
10
|
+
|
|
11
|
+
def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> ExecutionPolicy:
|
|
12
|
+
if not parameters.Has("name"):
|
|
13
|
+
raise RuntimeError(f"IndependentAnalysisExecutionPolicy instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
|
|
14
|
+
if not parameters.Has("settings"):
|
|
15
|
+
raise RuntimeError(f"IndependentAnalysisExecutionPolicy instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")
|
|
16
|
+
|
|
17
|
+
return IndependentAnalysisExecutionPolicy(parameters["name"].GetString(), model, parameters["settings"])
|
|
18
|
+
|
|
19
|
+
class IndependentAnalysisExecutionPolicy(ExecutionPolicy):
|
|
20
|
+
def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters):
|
|
21
|
+
super().__init__(name)
|
|
22
|
+
|
|
23
|
+
self.model = model
|
|
24
|
+
|
|
25
|
+
default_settings = Kratos.Parameters("""{
|
|
26
|
+
"analysis_module" : "KratosMultiphysics",
|
|
27
|
+
"analysis_type" : "",
|
|
28
|
+
"analysis_model_part_name": "",
|
|
29
|
+
"analysis_settings" : {}
|
|
30
|
+
}""")
|
|
31
|
+
|
|
32
|
+
parameters.ValidateAndAssignDefaults(default_settings)
|
|
33
|
+
|
|
34
|
+
self.analysis_module = parameters["analysis_module"].GetString()
|
|
35
|
+
self.analysis_type = parameters["analysis_type"].GetString()
|
|
36
|
+
self.analysis_settings = parameters["analysis_settings"]
|
|
37
|
+
self.analysis_model_part_name = parameters["analysis_model_part_name"].GetString()
|
|
38
|
+
|
|
39
|
+
if self.analysis_module == "KratosMultiphysics":
|
|
40
|
+
self.analysis_full_module, self.analysis_type = GetClassModuleFromKratos(self.analysis_type)
|
|
41
|
+
else:
|
|
42
|
+
self.analysis_full_module = f"{self.analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(self.analysis_type)}"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def Initialize(self) -> None:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
def Check(self) -> None:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
def Finalize(self) -> None:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
def Execute(self):
|
|
55
|
+
analysis_type = getattr(import_module(self.analysis_full_module), self.analysis_type)
|
|
56
|
+
if AnalysisStage in analysis_type.mro():
|
|
57
|
+
# the analysis type is derived from AnalysisStage
|
|
58
|
+
self.current_analysis: AnalysisStage = getattr(import_module(self.analysis_full_module), self.analysis_type)(self.model, self.analysis_settings.Clone())
|
|
59
|
+
elif Orchestrator in analysis_type.mro():
|
|
60
|
+
# the analysis type is derive from the Orchestrator
|
|
61
|
+
project = Project(self.analysis_settings.Clone())
|
|
62
|
+
self.current_analysis: Orchestrator = getattr(import_module(self.analysis_full_module), self.analysis_type)(project)
|
|
63
|
+
|
|
64
|
+
self.current_analysis.Run()
|
|
65
|
+
|
|
66
|
+
def GetAnalysisModelPart(self):
|
|
67
|
+
if self.current_analysis is not None:
|
|
68
|
+
if isinstance(self.current_analysis, AnalysisStage):
|
|
69
|
+
if self.analysis_model_part_name == "" or self.analysis_model_part_name == self.current_analysis._GetSolver().GetComputingModelPart().FullName():
|
|
70
|
+
return self.current_analysis._GetSolver().GetComputingModelPart()
|
|
71
|
+
else:
|
|
72
|
+
raise RuntimeError(f"The specified analysis model part name mismatch [ specified analysis model part name = {self.analysis_model_part_name}, used analysis model part name = {self.current_analysis._GetSolver().GetComputingModelPart().FullName()} ].")
|
|
73
|
+
elif isinstance(self.current_analysis, Orchestrator):
|
|
74
|
+
return self.current_analysis.GetProject().GetModel()[self.analysis_model_part_name]
|
|
75
|
+
else:
|
|
76
|
+
raise RuntimeError(f"Unsupported analysis type = {self.current_analysis}.")
|
|
77
|
+
else:
|
|
78
|
+
raise RuntimeError("The analysis is not run yet.")
|