Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OptApp] Adding combined response function #12432

Merged
merged 5 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from typing import Optional

import KratosMultiphysics as Kratos
import KratosMultiphysics.OptimizationApplication as KratosOA
from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction
from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes
from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem
from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView

def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ResponseFunction:
if not parameters.Has("name"):
raise RuntimeError(f"CombinedResponseFunction instantiation requires a \"name\" in parameters [ parameters = {parameters}].")
if not parameters.Has("settings"):
raise RuntimeError(f"CombinedResponseFunction instantiation requires a \"settings\" in parameters [ parameters = {parameters}].")

return CombinedResponseFunction(parameters["name"].GetString(), model, parameters["settings"], optimization_problem)

class CombinedResponseFunction(ResponseFunction):
"""Response function to combine multiple response functions.

This response function can combine multiple response functions to a single response function.
Following methods are used to combine the response values:
1. weighted sum - Weighted summation of responses list is used as the combined response function value.

"""
def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem):
super().__init__(name)

default_settings = Kratos.Parameters("""{
"combining_method" : "sum",
"combining_responses": [
{
"response_name" : "",
"response_weight": 0.0
}
]
}""")
parameters.ValidateAndAssignDefaults(default_settings)
self.combining_method = parameters["combining_method"].GetString()

self.model = model
self.model_part: Optional[Kratos.ModelPart] = None
self.optimization_problem = optimization_problem

self.list_of_responses: 'list[tuple[ResponseFunction, float]]' = []
for response_params in parameters["combining_responses"].values():
response_params.ValidateAndAssignDefaults(default_settings["combining_responses"].values()[0])
response_name = response_params["response_name"].GetString()

if response_name not in [response.GetName() for response in optimization_problem.GetListOfResponses()]:
raise RuntimeError(f"\"{response_name}\" not found in the optimization problem. Please check whether this reponse is defined before the \"{self.GetName()}\".")

self.list_of_responses.append(
(
self.optimization_problem.GetResponse(response_name),
response_params["response_weight"].GetDouble()
))

if len(self.list_of_responses) == 0:
raise RuntimeError(f"Combined response \"{self.GetName()}\" does not have any responses to combine.")

def GetImplementedPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]':
variables_list: 'list[SupportedSensitivityFieldVariableTypes]' = []
for response, _ in self.list_of_responses:
variables_list.extend(response.GetImplementedPhysicalKratosVariables())
return list(set(variables_list))

def GetEvaluatedModelPart(self) -> Kratos.ModelPart:
if all([response.GetEvaluatedModelPart() != None for response, _ in self.list_of_responses]):
raise RuntimeError(f"Mixing of adjoint and direct responses are prohibited.")

if self.model_part == None:
evaluated_model_part_names = [response.GetEvaluatedModelPart().FullName() for response, _ in self.list_of_responses]
model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"response_{self.GetName()}", evaluated_model_part_names, False)
self.model_part = model_part_operation.GetModelPart()
return self.model_part

def GetAnalysisModelPart(self) -> Kratos.ModelPart:
if all([response.GetAnalysisModelPart() != None for response, _ in self.list_of_responses]):
raise RuntimeError(f"Mixing of adjoint and direct responses are prohibited.")

if self.model_part == None:
evaluated_model_part_names = [response.GetAnalysisModelPart().FullName() for response, _ in self.list_of_responses]
model_part_operation = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, f"response_{self.GetName()}", evaluated_model_part_names, False)
self.model_part = model_part_operation.GetModelPart()
return self.model_part

def Initialize(self) -> None:
for response, _ in self.list_of_responses:
response.Initialize()

component_data_view = ComponentDataView(self, self.optimization_problem)
component_data_view.SetDataBuffer(1)
self.buffered_data = component_data_view.GetBufferedData()
self.unbuffered_data = component_data_view.GetUnBufferedData()

def Check(self) -> None:
for response, _ in self.list_of_responses:
response.Check()

def Finalize(self) -> None:
for response, _ in self.list_of_responses:
response.Finalize()

def CalculateValue(self) -> float:
if self.combining_method == "sum":
value = 0.0
for response, weight in self.list_of_responses:
response_value = response.CalculateValue()
value += response_value * weight
self.buffered_data.SetValue(f"{response.GetName()}", response_value, overwrite=True)
else:
raise RuntimeError(f"Unsupported combining_method = \"{self.combining_method}\". Followings are supported:\n\tsum")
return value

def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None:
# make everything zeros
for physical_variable, collective_expression in physical_variable_collective_expressions.items():
for container_expression in collective_expression.GetContainerExpressions():
Kratos.Expression.LiteralExpressionIO.SetDataToZero(container_expression, physical_variable)

for response_function, weight in self.list_of_responses:
# get the map for the response function
sub_physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {}
for physical_variable, collective_expression in physical_variable_collective_expressions.items():
if physical_variable in response_function.GetImplementedPhysicalKratosVariables():
sub_physical_variable_collective_expressions[physical_variable] = collective_expression.Clone()

# calculate the gradients
response_function.CalculateGradient(sub_physical_variable_collective_expressions)

# now aggregate the gradients
for physical_variable, local_collective_expression in sub_physical_variable_collective_expressions.items():
self.unbuffered_data.SetValue(f"d{response_function.GetName()}_d{physical_variable.Name()}", local_collective_expression, overwrite=True)
combined_collective_expression = physical_variable_collective_expressions[physical_variable]
for i, local_container_expression in enumerate(local_collective_expression.GetContainerExpressions()):
local_exp = local_container_expression
combined_container_exp = combined_collective_expression.GetContainerExpressions()[i]

if self.combining_method == "sum":
combined_container_exp.SetExpression(Kratos.Expression.Utils.Collapse(combined_container_exp + local_exp * weight).GetExpression())
else:
raise RuntimeError(f"Unsupported combining_method = \"{self.combining_method}\". Followings are supported:\n\tsum")
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
Begin Properties 1

End Properties

Begin Properties 2

End Properties

Begin Nodes
1 -0.5 -0.5 0
2 -0.5 0.5 0
3 0.5 0.5 0
4 0.5 -0.5 0
5 -0.5 1.5 0
6 0.5 1.5 0
7 -0.5 2.5 0
8 0.5 2.5 0
9 -0.5 3.5 0
10 0.5 3.5 0
11 1.5 0.5 0
12 1.5 -0.5 0
13 1.5 1.5 0
14 1.5 2.5 0
15 1.5 3.5 0
16 2.5 0.5 0
17 2.5 -0.5 0
18 2.5 1.5 0
19 2.5 2.5 0
20 2.5 3.5 0
21 3.5 0.5 0
22 3.5 -0.5 0
23 3.5 1.5 0
24 3.5 2.5 0
25 3.5 3.5 0
End Nodes

Begin Elements HelmholtzVectorSurfaceElement3D4N
1 1 1 2 3 4
2 1 2 5 6 3
3 1 5 7 8 6
4 1 7 9 10 8
5 1 4 3 11 12
6 1 3 6 13 11
7 1 6 8 14 13
8 1 8 10 15 14
9 1 12 11 16 17
10 1 11 13 18 16
11 1 13 14 19 18
12 1 14 15 20 19
13 1 17 16 21 22
14 1 16 18 23 21
15 1 18 19 24 23
16 1 19 20 25 24
End Elements

Begin Conditions LineCondition3D2N
1 2 1 2
2 2 22 21
3 2 2 5
4 2 21 23
5 2 5 7
6 2 23 24
7 2 7 9
8 2 24 25
9 2 1 4
10 2 9 10
11 2 4 12
12 2 10 15
13 2 12 17
14 2 15 20
15 2 17 22
16 2 20 25
End Conditions

Begin SubModelPart sensitivity_condition_1
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
10
15
20
End SubModelPartNodes
Begin SubModelPartElements
End SubModelPartElements
Begin SubModelPartConditions
12
14
End SubModelPartConditions
End SubModelPart

Begin SubModelPart sensitivity_element_4
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
11
13
16
18
21
23
End SubModelPartNodes
Begin SubModelPartElements
10
14
End SubModelPartElements
Begin SubModelPartConditions
End SubModelPartConditions
End SubModelPart

Begin SubModelPart sensitivity_element_3
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
11
12
16
17
21
22
End SubModelPartNodes
Begin SubModelPartElements
9
13
End SubModelPartElements
Begin SubModelPartConditions
End SubModelPartConditions
End SubModelPart

Begin SubModelPart sensitivity_element_1
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
1
2
3
4
11
12
End SubModelPartNodes
Begin SubModelPartElements
1
5
End SubModelPartElements
Begin SubModelPartConditions
11
End SubModelPartConditions
End SubModelPart

Begin SubModelPart sensitivity_element_2
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
1
2
3
4
11
12
16
17
End SubModelPartNodes
Begin SubModelPartElements
1
5
9
End SubModelPartElements
Begin SubModelPartConditions
End SubModelPartConditions
End SubModelPart

Begin SubModelPart evaluated_element_3
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
3
6
11
13
16
18
End SubModelPartNodes
Begin SubModelPartElements
6
10
End SubModelPartElements
Begin SubModelPartConditions
End SubModelPartConditions
End SubModelPart

Begin SubModelPart evaluated_element_2
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
3
6
11
13
14
16
18
19
End SubModelPartNodes
Begin SubModelPartElements
6
10
11
End SubModelPartElements
Begin SubModelPartConditions
End SubModelPartConditions
End SubModelPart

Begin SubModelPart evaluated_element_1
Begin SubModelPartData
End SubModelPartData
Begin SubModelPartTables
End SubModelPartTables
Begin SubModelPartNodes
3
4
6
8
11
12
13
14
16
17
End SubModelPartNodes
Begin SubModelPartElements
5
7
9
End SubModelPartElements
Begin SubModelPartConditions
11
13
End SubModelPartConditions
End SubModelPart

Loading
Loading