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

[ROM] Unify ROM solver #9490

Merged
merged 11 commits into from
Jan 3, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class ROMSolver(ConvectionDiffusionStationarySolver):
"""

def __init__(self, model, custom_settings):
KratosMultiphysics.Logger.PrintWarning('\x1b[1;31m[DEPRECATED CLASS] \x1b[0m',"\'convection_diffusion_stationary_rom_solver\'", "class is deprecated. Use the generic\'RomSolver\' one instead.")

super(ROMSolver, self).__init__(model, custom_settings)
KratosMultiphysics.Logger.PrintInfo("::[ROMSolver]:: ", "Construction finished")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class ROMSolver(ConvectionDiffusionTransientSolver):
"""

def __init__(self, model, custom_settings):
KratosMultiphysics.Logger.PrintWarning('\x1b[1;31m[DEPRECATED CLASS] \x1b[0m',"\'convection_diffusion_transient_rom_solver\'", "class is deprecated. Use the generic\'RomSolver\' one instead.")

super(ROMSolver, self).__init__(model, custom_settings)
KratosMultiphysics.Logger.PrintInfo("::[ROMSolver]:: ", "Construction finished")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def CreateSolver(model, custom_settings):
class ROMSolver(NavierStokesSolverMonolithic):

def __init__(self, model, custom_settings):
KratosMultiphysics.Logger.PrintWarning('\x1b[1;31m[DEPRECATED CLASS] \x1b[0m',"\'navier_stokes_solver_vmsmonolithic_rom\'", "class is deprecated. Use the generic\'RomSolver\' one instead.")

super().__init__(model, custom_settings)
KratosMultiphysics.Logger.PrintInfo("::[ROMSolver]:: ", "Construction finished")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import sys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend coming up with a better name rather than prepending with new_
remember how long we were stuck with the new_linear_solver_factory 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄 Considering that this is a small research application I don't think we'll need to change keep backwards compatibility for a very long period of time. Indeed, the plan is to remove the old stuff ASAP. I'd keep the new_ to constantly remind us to do it 😄.

import importlib

import KratosMultiphysics
from KratosMultiphysics import kratos_utilities
from KratosMultiphysics.RomApplication import rom_solver

def CreateSolverByParameters(model, solver_settings, parallelism, analysis_stage_module_name):

if not isinstance(model, KratosMultiphysics.Model):
raise Exception("input is expected to be provided as a Kratos Model object")

if not isinstance(solver_settings, KratosMultiphysics.Parameters):
raise Exception("input is expected to be provided as a Kratos Parameters object")

# Get the corresponding application from the analysis_stage path
split_analysis_stage_module_name = analysis_stage_module_name.split('.')
application_module_name = split_analysis_stage_module_name[0] + "." + split_analysis_stage_module_name[1]
if not kratos_utilities.CheckIfApplicationsAvailable(split_analysis_stage_module_name[1]):
raise Exception("Module {} is not available.".format(application_module_name))

# Filter and retrieve the Python solvers wrapper from the corresponding application
#TODO: This filtering wouldn't be required if we were using a unified solvers wrapper module name
if application_module_name == "KratosMultiphysics.FluidDynamicsApplication":
solvers_wrapper_module_module_name = "python_solvers_wrapper_fluid"
elif application_module_name == "KratosMultiphysics.StructuralMechanicsApplication":
solvers_wrapper_module_module_name = "python_solvers_wrapper_structural"
elif application_module_name == "KratosMultiphysics.ConvectionDiffusionApplication":
solvers_wrapper_module_module_name = "python_solvers_wrapper_convection_diffusion"
else:
err_msg = "Python module \'{0}\' is not available. Make sure \'{1}\' is compiled.".format(application_module_name, split_analysis_stage_module_name[1])
raise Exception(err_msg)
solvers_wrapper_module = importlib.import_module(application_module_name + "." + solvers_wrapper_module_module_name)

# Create a prototype class instance and get the module and name of the solver to be used as base
# Note that an auxiliary Kratos parameter settings without the rom_settings field is created to avoid the defaults error thrown
# Note that an auxiliary Kratos model is also created to avoid creating the main_model_part in the prototype class instance
#TODO: We could do the same exercise as we do in the stage (module_name to ClassName equal to ModuleName if we standarize the solver names)
aux_solver_settings = solver_settings.Clone()
aux_solver_settings.RemoveValue("rom_settings")
aux_base_solver_instance = solvers_wrapper_module.CreateSolverByParameters(KratosMultiphysics.Model(), aux_solver_settings, parallelism)

# Create the ROM solver from the base solver
rom_solver_instance = rom_solver.CreateSolver(type(aux_base_solver_instance), model, solver_settings)

return rom_solver_instance

def CreateSolver(model, custom_settings):

if (type(model) != KratosMultiphysics.Model):
raise Exception("input is expected to be provided as a Kratos Model object")

if (type(custom_settings) != KratosMultiphysics.Parameters):
raise Exception("input is expected to be provided as a Kratos Parameters object")

parallelism = custom_settings["problem_data"]["parallel_type"].GetString()
analysis_stage = custom_settings["analysis_stage"].GetString()
solver_settings = custom_settings["solver_settings"]

return CreateSolverByParameters(model, solver_settings, parallelism, analysis_stage)

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

def CreateSolverByParameters(model, solver_settings, parallelism):

KratosMultiphysics.Logger.PrintWarning('\x1b[1;31m[DEPRECATED CLASS] \x1b[0m',"\'python_solvers_wrapper_rom\'", "module is deprecated. Use the generic\'new_python_solvers_wrapper_rom\' one instead.")

if (type(model) != KratosMultiphysics.Model):
raise Exception("input is expected to be provided as a Kratos Model object")

Expand Down
10 changes: 5 additions & 5 deletions applications/RomApplication/python_scripts/rom_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import KratosMultiphysics
import KratosMultiphysics.RomApplication as KratosROM
from KratosMultiphysics.RomApplication import python_solvers_wrapper_rom
from KratosMultiphysics.RomApplication import new_python_solvers_wrapper_rom
from KratosMultiphysics.RomApplication.empirical_cubature_method import EmpiricalCubatureMethod

def CreateRomAnalysisInstance(cls, global_model, parameters, hyper_reduction_element_selector = None):
Expand Down Expand Up @@ -33,10 +34,9 @@ def _CreateSolver(self):
self.project_parameters["solver_settings"].AddValue("rom_settings", rom_settings["rom_settings"])

# Create the ROM solver
return python_solvers_wrapper_rom.CreateSolverByParameters(
return new_python_solvers_wrapper_rom.CreateSolver(
self.model,
self.project_parameters["solver_settings"],
self.project_parameters["problem_data"]["parallel_type"].GetString())
self.project_parameters)

def _GetSimulationName(self):
return "::[ROM Simulation]:: "
Expand All @@ -53,7 +53,7 @@ def ModifyAfterSolverInitialize(self):
# Get the ROM data from RomParameters.json
data = json.load(f)
nodal_modes = data["nodal_modes"]
nodal_dofs = len(data["rom_settings"]["nodal_unknowns"])
nodal_dofs = len(self.project_parameters["solver_settings"]["rom_settings"]["nodal_unknowns"].GetStringArray())
rom_dofs = self.project_parameters["solver_settings"]["rom_settings"]["number_of_rom_dofs"].GetInt()

# Set the nodal ROM basis
Expand Down Expand Up @@ -134,4 +134,4 @@ def ModifyAfterSolverInitialize(self):
global_model = KratosMultiphysics.Model()
simulation = CreateRomAnalysisInstance(analysis_stage_class, global_model, parameters)
# simulation = CreateHRomAnalysisInstance(analysis_stage_class, global_model, parameters)
simulation.Run()
simulation.Run()
58 changes: 58 additions & 0 deletions applications/RomApplication/python_scripts/rom_solver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Importing the Kratos Library
import KratosMultiphysics

# Import applications
import KratosMultiphysics.RomApplication as KratosROM

def CreateSolver(cls, model, custom_settings):
class ROMSolver(cls):
"""ROM solver generic main class.
This class serves as a generic class to make a standard Kratos solver ROM-compatible.
It extends the default parameters to include the \'rom_settings\' and overrides the
creation of the builder and solver to use the ROM one.
"""

def __init__(self, model, custom_settings):
super().__init__(model, custom_settings)
KratosMultiphysics.Logger.PrintInfo("::[ROMSolver]:: ", "Construction finished")

@classmethod
def GetDefaultParameters(cls):
default_settings = KratosMultiphysics.Parameters("""{
"rom_settings": {
"nodal_unknowns": [],
"number_of_rom_dofs": 0
}
}""")
default_settings.AddMissingParameters(super().GetDefaultParameters())
return default_settings

def _CreateBuilderAndSolver(self):
linear_solver = self._GetLinearSolver()
rom_parameters = self._ValidateAndReturnRomParameters()
builder_and_solver = KratosROM.ROMBuilderAndSolver(linear_solver, rom_parameters)
return builder_and_solver

def _ValidateAndReturnRomParameters(self):
# Check that the number of ROM DOFs has been provided
n_rom_dofs = self.settings["rom_settings"]["number_of_rom_dofs"].GetInt()
if not n_rom_dofs > 0:
err_msg = "\'number_of_rom_dofs\' in \'rom_settings\' is {}. Please set a larger than zero value.".format(n_rom_dofs)
raise Exception(err_msg)

# Check if the nodal unknowns have been provided by the user
# If not, take the DOFs list from the base solver
nodal_unknowns = self.settings["rom_settings"]["nodal_unknowns"].GetStringArray()
if len(nodal_unknowns) == 0:
solver_dofs_list = self.GetDofsList()
if not len(solver_dofs_list) == 0:
self.settings["rom_settings"]["nodal_unknowns"].SetStringArray(solver_dofs_list)
else:
err_msg = "\'nodal_unknowns\' in \'rom_settings\' is not provided and there is a not-valid implementation in base solver."
err_msg += " Please manually set \'nodal_unknowns\' in \'rom_settings\'."
raise Exception(err_msg)

# Return the validated ROM parameters
return self.settings["rom_settings"]

return ROMSolver(model, custom_settings)
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class ROMSolver(ImplicitMechanicalSolver):
"""

def __init__(self, main_model_part, custom_settings):
KratosMultiphysics.Logger.PrintWarning('\x1b[1;31m[DEPRECATED CLASS] \x1b[0m',"\'structural_mechanics_implicit_dynamic_rom_solver\'", "class is deprecated. Use the generic\'RomSolver\' one instead.")

super(ROMSolver, self).__init__(main_model_part, custom_settings)
KratosMultiphysics.Logger.PrintInfo("::[ROMSolver]:: ", "Construction finished")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class ROMSolver(StaticMechanicalSolver):
"""

def __init__(self, main_model_part, custom_settings):
KratosMultiphysics.Logger.PrintWarning('\x1b[1;31m[DEPRECATED CLASS] \x1b[0m',"\'stuctural_mechanics_static_rom_solver\'", "class is deprecated. Use the generic\'RomSolver\' one instead.")

super(ROMSolver, self).__init__(main_model_part, custom_settings)
KratosMultiphysics.Logger.PrintInfo("::[ROMSolver]:: ", "Construction finished")

Expand Down