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

[Core] Project-based multistage #11355

Merged
merged 56 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
bad13d2
Create GetFinalData
rubenzorrilla Jun 22, 2023
b32fc3b
Restart support
rubenzorrilla Jun 22, 2023
f7f3577
Register stages
rubenzorrilla Jun 22, 2023
43e2b55
Registry based instantiation and custom
rubenzorrilla Jun 22, 2023
a234fcd
Output validated settings
rubenzorrilla Jun 22, 2023
f8a818d
Remove useless comment
rubenzorrilla Jun 22, 2023
2c21077
Fix checkpoint list
rubenzorrilla Jun 22, 2023
9cc4215
More descriptive error
rubenzorrilla Jun 22, 2023
aaa5072
Discussion changes
rubenzorrilla Jun 26, 2023
9eabcab
Merge branch 'master' into core/multistage-project
rubenzorrilla Jun 29, 2023
8414844
FinalData agreed name
rubenzorrilla Jun 29, 2023
ac27c3a
Major advances (not working yet)
rubenzorrilla Jun 30, 2023
5975031
More advances (working)
rubenzorrilla Jun 30, 2023
e1a4106
Use registry
rubenzorrilla Jun 30, 2023
ca8d87a
Type hints
rubenzorrilla Jun 30, 2023
886748f
Renaming
rubenzorrilla Jul 5, 2023
48ac60b
Merge branch 'master' into core/multistage-project
rubenzorrilla Jul 5, 2023
8914914
Final discussion changes
rubenzorrilla Jul 5, 2023
275821b
Merge branch 'master' into core/multistage-project
rubenzorrilla Jul 5, 2023
3477001
Merge branch 'master' into core/multistage-project
rubenzorrilla Jul 7, 2023
af21953
Correct imports
rubenzorrilla Jul 7, 2023
2ef69aa
Merge branch 'master' into core/multistage-project
rubenzorrilla Jul 7, 2023
c5adf05
Some of Pooyan's suggestions
rubenzorrilla Jul 7, 2023
e45fe13
update helper utils
sunethwarna Jul 7, 2023
8b5dcdd
update stepping analysis
sunethwarna Jul 7, 2023
38e04c0
update independent analysis execution policy
sunethwarna Jul 7, 2023
04a5093
update kratos analysis execution policy
sunethwarna Jul 7, 2023
1f19695
update tests
sunethwarna Jul 7, 2023
0d4d8a1
minor
sunethwarna Jul 7, 2023
b915e77
Update applications/OptimizationApplication/python_scripts/utilities/…
sunethwarna Jul 8, 2023
528d9ea
Update kratos/python_scripts/multistage_orchestrators/multistage_orch…
rubenzorrilla Jul 10, 2023
57c7813
Merge pull request #11371 from KratosMultiphysics/optapp/fix_for_ocha…
sunethwarna Jul 10, 2023
64bac3f
Update kratos/python_scripts/project.py
rubenzorrilla Jul 10, 2023
59390eb
Update kratos/python_scripts/project.py
rubenzorrilla Jul 10, 2023
396509c
Update kratos/python_scripts/project.py
rubenzorrilla Jul 10, 2023
85915a0
Update kratos/python_scripts/project.py
rubenzorrilla Jul 10, 2023
52fd8cc
Update kratos/python_scripts/project.py
rubenzorrilla Jul 10, 2023
652e5aa
@philbucher suggestions
rubenzorrilla Jul 10, 2023
6734444
Update kratos/python_scripts/project.py
rubenzorrilla Jul 10, 2023
535577d
Merge branch 'core/multistage-project' of https://github.com/KratosMu…
rubenzorrilla Jul 10, 2023
9c3c6b8
Project type hints completed
rubenzorrilla Jul 10, 2023
f3d34e1
Update kratos/python_scripts/multistage_orchestrators/multistage_orch…
rubenzorrilla Jul 10, 2023
495b8bd
Type hints and encapsulating settings
rubenzorrilla Jul 10, 2023
4243919
stage_settings leftowver
rubenzorrilla Jul 10, 2023
62e3e69
Remove multistage keyword from names
rubenzorrilla Jul 10, 2023
abf6843
Pooyan's documentation request
rubenzorrilla Jul 10, 2023
41165dd
Test
rubenzorrilla Jul 10, 2023
743d714
Merge branch 'core/multistage-project' of https://github.com/KratosMu…
rubenzorrilla Jul 10, 2023
057a2ab
TODO comment
rubenzorrilla Jul 10, 2023
d4c3e35
Adding test to suite
rubenzorrilla Jul 10, 2023
32ae92f
Merge branch 'master' into core/multistage-project
rubenzorrilla Jul 10, 2023
765d021
Missing import in test_KratosCore.py
rubenzorrilla Jul 10, 2023
41405d4
Better documentation
rubenzorrilla Jul 11, 2023
49dabec
Update kratos/python_scripts/orchestrators/orchestrator.py
rubenzorrilla Jul 11, 2023
f61a82e
@philbucher's suggestion on the types
rubenzorrilla Jul 11, 2023
dd213d7
Import suggestion
rubenzorrilla Jul 11, 2023
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
Expand Up @@ -5,4 +5,10 @@
python_processes_to_be_registered = [
"apply_boussinesq_force_process.ApplyBoussinesqForceProcess",
"apply_inlet_process.ApplyInletProcess"
]
]

python_stages_to_be_registered = [
"fluid_dynamics_analysis.FluidDynamicsAnalysis"
]

python_orchestrators_to_be_registered = []
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import KratosMultiphysics as Kratos
from KratosMultiphysics.analysis_stage import AnalysisStage
from KratosMultiphysics.multistage_analysis import MultistageAnalysis
from KratosMultiphysics.project import Project
from KratosMultiphysics.orchestrators.orchestrator import Orchestrator
from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy
from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetClassModuleFromKratos

Expand All @@ -22,21 +23,24 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters
self.model = model

default_settings = Kratos.Parameters("""{
"analysis_module" : "KratosMultiphysics",
"analysis_type" : "",
"analysis_settings": {}
"analysis_module" : "KratosMultiphysics",
"analysis_type" : "",
"analysis_model_part_name": "",
"analysis_settings" : {}
}""")

parameters.ValidateAndAssignDefaults(default_settings)

self.analysis_module = parameters["analysis_module"].GetString()
self.analysis_type = parameters["analysis_type"].GetString()
self.analysis_settings = parameters["analysis_settings"]
self.analysis_model_part_name = parameters["analysis_model_part_name"].GetString()

if self.analysis_module == "KratosMultiphysics":
self.analysis_module = GetClassModuleFromKratos(self.analysis_type)
self.analysis_full_module, self.analysis_type = GetClassModuleFromKratos(self.analysis_type)
else:
self.analysis_full_module = f"{self.analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(self.analysis_type)}"

self.analysis_full_module = f"{self.analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(self.analysis_type)}"

def Initialize(self) -> None:
pass
Expand All @@ -48,11 +52,27 @@ def Finalize(self) -> None:
pass

def Execute(self):
self.current_analysis: Union[AnalysisStage, MultistageAnalysis] = getattr(import_module(self.analysis_full_module), self.analysis_type)(self.model, self.analysis_settings.Clone())
analysis_type = getattr(import_module(self.analysis_full_module), self.analysis_type)
if AnalysisStage in analysis_type.mro():
# the analysis type is derrived from AnalysisStage
self.current_analysis: AnalysisStage = getattr(import_module(self.analysis_full_module), self.analysis_type)(self.model, self.analysis_settings.Clone())
elif Orchestrator in analysis_type.mro():
# the analysis type is derrive from the Orchestrator
project = Project(self.analysis_settings.Clone())
self.current_analysis: Orchestrator = getattr(import_module(self.analysis_full_module), self.analysis_type)(project)

self.current_analysis.Run()

def GetAnalysisModelPart(self):
if self.current_analysis is not None:
return self.current_analysis._GetSolver().GetComputingModelPart()
if isinstance(self.current_analysis, AnalysisStage):
if self.analysis_model_part_name == "" or self.analysis_model_part_name == self.current_analysis._GetSolver().GetComputingModelPart().FullName():
return self.current_analysis._GetSolver().GetComputingModelPart()
else:
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()} ].")
elif isinstance(self.current_analysis, Orchestrator):
return self.current_analysis.GetProject().GetModel()[self.analysis_model_part_name]
else:
raise RuntimeError(f"Unsupported analysis type = {self.current_analysis}.")
else:
raise RuntimeError("The analysis is not run yet.")
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters
analysis_settings = parameters["analysis_settings"]

if analysis_module == "KratosMultiphysics":
analysis_module = GetClassModuleFromKratos(analysis_type)
analysis_full_module, analysis_type = GetClassModuleFromKratos(analysis_type)
else:
analysis_full_module = f"{analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(analysis_type)}"

self.model_parts: 'list[Kratos.ModelPart]' = []
analysis_full_module = f"{analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(analysis_type)}"
self.analysis: AnalysisStage = getattr(import_module(analysis_full_module), analysis_type)(self.model, analysis_settings.Clone())

analysis_output_settings = self.parameters["analysis_output_settings"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from KratosMultiphysics.analysis_stage import AnalysisStage
from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy
from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import GetClassModuleFromKratos
from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem

def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> ExecutionPolicy:
if not parameters.Has("name"):
Expand Down Expand Up @@ -33,10 +32,11 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters
analysis_settings = parameters["analysis_settings"]

if analysis_module == "KratosMultiphysics":
analysis_module = GetClassModuleFromKratos(analysis_type)
analysis_full_module, analysis_type = GetClassModuleFromKratos(analysis_type)
else:
analysis_full_module = f"{analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(analysis_type)}"

self.model_parts = []
analysis_full_module = f"{analysis_module}.{Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(analysis_type)}"
self.analysis: AnalysisStage = getattr(import_module(analysis_full_module), analysis_type)(self.model, analysis_settings.Clone())

def GetAnalysisModelPart(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,35 @@
from KratosMultiphysics.kratos_utilities import GetKratosMultiphysicsPath
from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes

def GetClassModuleFromKratos(class_name: str) -> str:
snake_case_class_name = Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(class_name)
def GetClassModuleFromKratos(full_class_name: str) -> str:
sub_module_paths = full_class_name.split(".")

if not sub_module_paths:
raise RuntimeError("Empty class names are not allowed.")

relative_sub_module = Kratos.StringUtilities.ConvertCamelCaseToSnakeCase(sub_module_paths[-1])
if len(sub_module_paths) > 1:
relative_sub_module = ".".join(sub_module_paths[:-1]) + f".{relative_sub_module}"

relative_sub_module_path = relative_sub_module.replace(".", "/")
kratos_path = GetKratosMultiphysicsPath()

# check whether it is in Kratos core
if Path(f"{kratos_path}/{snake_case_class_name}.py").is_file():
return "KratosMultiphysics"
if Path(f"{kratos_path}/{relative_sub_module_path}.py").is_file():
return f"KratosMultiphysics.{relative_sub_module}", sub_module_paths[-1]

# now check if it is found in any of the compiled applications
list_of_available_appliacations = GetListOfAvailableApplications()

module_application = ""
for application in list_of_available_appliacations:
if Path(f"{kratos_path}/{application}/{snake_case_class_name}.py").is_file():
module_application = f"KratosMultiphysics.{application}"
if Path(f"{kratos_path}/{application}/{relative_sub_module_path}.py").is_file():
module_application = f"KratosMultiphysics.{application}.{relative_sub_module}"

if module_application != "":
return module_application
return module_application, sub_module_paths[-1]
else:
raise RuntimeError(f"{class_name} is not found in KratosMultiphysics core or any of the available application root directories in Kratos. Available applications:\n\t" + "\n\t".join(list_of_available_appliacations))
raise RuntimeError(f"{full_class_name} is not found in KratosMultiphysics core or any of the available application directories in Kratos. Available applications:\n\t" + "\n\t".join(list_of_available_appliacations))

def CallOnAll(list_of_objects: 'list[Any]', method: Any, *args, **kwargs):
for obj in list_of_objects:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ class TestExecutionPolicies(kratos_unittest.TestCase):
def test_IndependentAnalysisExecutionPolicy(self):
model = Kratos.Model()
parameters = Kratos.Parameters("""{
"name" : "test",
"type": "independent_analysis_execution_policy",
"name" : "test",
"type" : "independent_analysis_execution_policy",
"settings": {
"analysis_type" : "MultistageAnalysis",
"analysis_type" : "orchestrators.SequentialOrchestrator",
"analysis_settings": {
"stages": [],
"execution_list":[]
"orchestrator": {
"settings": {
"stage_checkpoints": false
}
},
"stages":[]
}
}
}""")
Expand Down
9 changes: 9 additions & 0 deletions kratos/python_interface/python_registry_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,13 @@
"assign_vector_variable_to_elements_process.AssignVectorVariableToElementsProcess",
"assign_vector_variable_to_entities_process.AssignVectorVariableToEntitiesProcess",
"assign_vector_variable_to_nodes_process.AssignVectorVariableToNodesProcess"
]

python_stages_to_be_registered = [
"analysis_stage.AnalysisStage"
]

python_orchestrators_to_be_registered = [
"orchestrators.orchestrator.Orchestrator",
"orchestrators.sequential_orchestrator.SequentialOrchestrator"
]
10 changes: 10 additions & 0 deletions kratos/python_interface/python_registry_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ def RegisterAll(PythonModuleName, PythonRegistryListModule):
RegisterModelersList(PythonModuleName, PythonRegistryListModule)
RegisterOperationsList(PythonModuleName, PythonRegistryListModule)
RegisterProcessesList(PythonModuleName, PythonRegistryListModule)
RegisterStagesList(PythonModuleName, PythonRegistryListModule)
RegisterOrchestratorsList(PythonModuleName, PythonRegistryListModule)

def RegisterModelersList(PythonModuleName, PythonRegistryListModule):
__CheckRegistryListIsInModule(PythonRegistryListModule, "modelers")
Expand All @@ -17,6 +19,14 @@ def RegisterProcessesList(PythonModuleName, PythonRegistryListModule):
__CheckRegistryListIsInModule(PythonRegistryListModule, "processes")
__RegisterItemList(PythonModuleName, PythonRegistryListModule.python_processes_to_be_registered, "Processes")

def RegisterStagesList(PythonModuleName, PythonRegistryListModule):
__CheckRegistryListIsInModule(PythonRegistryListModule, "stages")
__RegisterItemList(PythonModuleName, PythonRegistryListModule.python_stages_to_be_registered, "Stages")

def RegisterOrchestratorsList(PythonModuleName, PythonRegistryListModule):
__CheckRegistryListIsInModule(PythonRegistryListModule, "orchestrators")
__RegisterItemList(PythonModuleName, PythonRegistryListModule.python_orchestrators_to_be_registered, "Orchestrators")

def __CheckRegistryListIsInModule(PythonRegistryListModule, ListKeyword):
list_variable_name = f"python_{ListKeyword}_to_be_registered"
if not list_variable_name in dir(PythonRegistryListModule):
Expand Down
28 changes: 22 additions & 6 deletions kratos/python_scripts/analysis_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ def Finalize(self):

def GetFinalData(self):
"""Returns the final data dictionary.

The main purpose of this function is to retrieve any data (in a key-value format) from outside the stage.
Note that even though it can be called at any point, it is intended to be called at the end of the stage run.
Note that even though it can be called at any point, it is intended to be called at the end of the stage run.
"""

return {}

def InitializeSolutionStep(self):
Expand Down Expand Up @@ -211,6 +211,22 @@ def ChangeMaterialProperties(self):
"""this function is where the user could change material parameters as a part of the solution step """
pass

def Save(self, serializer: KratosMultiphysics.StreamSerializer) -> None:
"""Serializes current analysis stage instance

This method is intended to make the class pure Python (pickable). This means serialize all the Kratos objects,
that is to say all the objects coming from Pybind, with the provided serializer. After the serialization, it is
required to assign None value to all the objects in order to make the class pickable.
"""
pass

def Load(self, serializer: KratosMultiphysics.StreamSerializer) -> None:
"""Loads current analysis stage instance

From the given serializer, this method restores current class from a pure Python status (pickable) to the one in the serializer.
"""
pass

def _GetSolver(self):
if not hasattr(self, '_solver'):
self._solver = self._CreateSolver()
Expand All @@ -220,13 +236,13 @@ def _CreateSolver(self):
"""Create the solver
"""
raise Exception("Creation of the solver must be implemented in the derived class.")

def _AdvanceTime(self):
""" Computes the following time
""" Computes the following time
The default method simply calls the solver
"""
return self._GetSolver().AdvanceInTime(self.time)

### Modelers
def _ModelersSetupGeometryModel(self):
# Import or generate geometry models from external input.
Expand Down
Loading
Loading