"""Solver parameters
.. autofunction:: iter_complete_params
.. autoclass:: Parameters
:members:
:private-members:
"""
from pathlib import Path
from typing import Iterable
import h5py
from fluiddyn.util import import_class, mpi
from fluiddyn.util.paramcontainer import ParamContainer
from .info import InfoSolverCore
[docs]
def iter_complete_params(params, info_solver, classes: dict or Iterable):
"""Iterate over a collection of classes and invoke the static method
``_complete_params_with_default`` to populate an instance of
:class:`Parameters` in-place.
Parameters
----------
params : :class:`fluidsim_core.params.Parameters` or its subclass
info_solver : :class:`fluidsim_core.info.InfoSolverCore` or its subclass
classes : dict or iterable
"""
if isinstance(classes, dict):
classes = [classes[key] for key in sorted(classes.keys())]
for Class in classes:
if hasattr(Class, "_complete_params_with_default"):
try:
Class._complete_params_with_default(params)
except TypeError:
try:
Class._complete_params_with_default(params, info_solver)
except TypeError as e:
e.args += ("for class: " + repr(Class),)
raise
[docs]
class Parameters(ParamContainer):
"""Contain the parameters."""
[docs]
@classmethod
def _create_params(cls, input_info_solver):
"""Create a Parameters instance from an InfoSolverCore instance."""
if isinstance(input_info_solver, InfoSolverCore):
info_solver = input_info_solver
elif hasattr(input_info_solver, "Simul"):
info_solver = input_info_solver.Simul.create_default_params()
else:
raise ValueError(
"Can not create params from input input_info_solver."
)
params = cls(tag="params")
dict_classes = {
"Solver": import_class(
info_solver.module_name, info_solver.class_name
)
}
dict_classes.update(info_solver.import_classes())
iter_complete_params(params, info_solver, dict_classes.values())
return params
[docs]
@classmethod
def _load_params_simul(cls, path=None, only_mpi_rank0=True):
"""Load the parameters and return a Parameters instance."""
if mpi.rank > 0 and not only_mpi_rank0:
params = None
else:
if path is None:
path = Path.cwd()
else:
path = Path(path)
path_xml = None
if path.is_dir():
path_xml = path / "params_simul.xml"
elif path.name.endswith(".xml"):
if not path.exists():
raise ValueError(f"The file {path} does not exists.")
path_xml = path
if path_xml is not None and path_xml.exists():
params = cls(path_file=path_xml)
else:
if path.is_file():
paths = [path]
else:
paths = list(path.glob("state_*"))
if paths:
path = sorted(paths)[0]
str_path = str(path)
if len(str_path) > 100:
str_path = "[...]" + str_path[-100:]
print("Loading params from file\n" + str_path)
with h5py.File(path, "r") as h5file:
params = cls(hdf5_object=h5file["/info_simul/params"])
else:
raise ValueError(f"No state files found in {path = }")
if mpi.nb_proc > 1 and not only_mpi_rank0:
params = mpi.comm.bcast(params, root=0)
return params
[docs]
@classmethod
def _load_info_solver(cls, path_dir=None):
"""Load the solver information, return an InfoSolverCore instance."""
if path_dir is None:
path_dir = Path.cwd()
if not isinstance(path_dir, Path):
path_dir = Path(path_dir)
if not path_dir.is_dir():
raise ValueError(str(path_dir) + " is not a directory")
path_info_solver = path_dir / "info_solver.xml"
if path_info_solver.exists():
return cls(path_file=str(path_info_solver))
paths = sorted(path_dir.glob("state_*"))
if not paths:
raise ValueError("No result files in dir " + str(path_dir))
str_path = path = str(paths[0])
if len(path) > 100:
str_path = "[...]" + path[-100:]
mpi.printby0("load params from file\n" + str_path)
with h5py.File(path, "r") as h5file:
return cls(hdf5_object=h5file["/info_simul/solver"])
def __ior__(self, other):
"""Defines operator `|=`
This operator performs a union with other Parameters instances.
In simpler words, merge missing attributes and children (members).
Do note, this does not check for mismatch in the parameter values.
Parameters
----------
other: Parameters
Another Parameters instance to look for missing members.
Returns
-------
Parameters
"""
if not isinstance(other, type(self)):
raise TypeError(
f"{type(other)}. Can only merge instances of Parameters."
)
params1 = self
params2 = other
# Merge attributes
diff_attribs = set(params2._key_attribs) - set(params1._key_attribs)
if len(diff_attribs) > 0:
print("Add parameter attributes: ", diff_attribs)
for attrib in diff_attribs:
params1._set_attrib(attrib, params2[attrib])
# Merge children
diff_children = set(params2._tag_children) - set(params1._tag_children)
internal_attribs = [
"attribs",
"children",
"key_attribs",
"tag",
"tag_children",
]
if len(diff_children) > 0:
print("Add parameter children: ", diff_children)
for child in diff_children:
child_attribs = params2[child]._make_dict()
# Clean up internal attributes from dictionary
list(map(child_attribs.__delitem__, internal_attribs))
params1._set_child(child, child_attribs)
# Recursive
for child in params2._tag_children:
params1[child] |= params2[child]
return self