diff --git a/ogs6py/_version.py b/ogs6py/_version.py
index d7d6487..7d7835b 100644
--- a/ogs6py/_version.py
+++ b/ogs6py/_version.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Provide a central version."""
-__version__ = "0.402"
+__version__ = "0.403"
diff --git a/ogs6py/classes/__init__.py b/ogs6py/classes/__init__.py
index d7ba3a5..dbc7925 100644
--- a/ogs6py/classes/__init__.py
+++ b/ogs6py/classes/__init__.py
@@ -1,3 +1,11 @@
+# Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
+# Distributed under a Modified BSD License.
+# See accompanying file LICENSE.txt or
+# http://www.opengeosys.org/project/license
+#
+
+# Author: Joerg Buchwald (Helmholtz Centre for Environmental Research GmbH - UFZ)
+
from . import display
from . import mesh
from . import geo
diff --git a/ogs6py/classes/build_tree.py b/ogs6py/classes/build_tree.py
index d5262ef..6a73ab8 100644
--- a/ogs6py/classes/build_tree.py
+++ b/ogs6py/classes/build_tree.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
@@ -6,51 +5,73 @@
http://www.opengeosys.org/project/license
"""
+
+
+from typing import TypeAlias
+
from lxml import etree as ET
+OptionalETElement: TypeAlias = (
+ ET.Element
+) # ToDo this should be Optional[ET.Element]
+
+
# pylint: disable=C0103, R0902, R0914, R0913
class BuildTree:
- """ helper class to create a nested dictionary
+ """helper class to create a nested dictionary
representing the xml structure
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
- def _get_root(self):
- root = self.tree.getroot()
- return root
+ def _get_root(self) -> ET.Element:
+ return self.tree.getroot()
@classmethod
- def _convertargs(cls, args):
+ def _convertargs(cls, args: dict[str, str]) -> None:
"""
convert arguments that are not lists or dictionaries to strings
"""
for item, value in args.items():
- if not isinstance(value, (list, dict)):
+ if not isinstance(value, list | dict):
args[item] = str(value)
@classmethod
- def populate_tree(cls, parent, tag, text=None, attr=None, overwrite=False):
+ def populate_tree(
+ cls,
+ parent: ET.Element,
+ tag: str,
+ text: str | None = None,
+ attr: dict[str, str] | None = None,
+ overwrite: bool = False,
+ ) -> ET.Element:
"""
method to create dictionary from an xml entity
"""
q = None
- if not tag is None:
+ if tag is not None:
if overwrite is True:
for child in parent:
if child.tag == tag:
q = child
if q is None:
q = ET.SubElement(parent, tag)
- if not text is None:
+ if text is not None:
q.text = str(text)
- if not attr is None:
+ if attr is not None:
for key, val in attr.items():
q.set(key, str(val))
return q
@classmethod
- def get_child_tag(cls, parent, tag, attr=None, attr_val=None):
+ def get_child_tag(
+ cls,
+ parent: ET.Element,
+ tag: str,
+ attr: dict[str, str] | None = None,
+ attr_val: str | None = None,
+ ) -> OptionalETElement:
"""
search for child tag based on tag and possible attributes
"""
@@ -65,7 +86,9 @@ def get_child_tag(cls, parent, tag, attr=None, attr_val=None):
return q
@classmethod
- def get_child_tag_for_type(cls, parent, tag, subtagval, subtag="type"):
+ def get_child_tag_for_type(
+ cls, parent: ET.Element, tag: str, subtagval: str, subtag: str = "type"
+ ) -> OptionalETElement:
"""
search for child tag based on subtag type
"""
@@ -73,7 +96,8 @@ def get_child_tag_for_type(cls, parent, tag, subtagval, subtag="type"):
for child in parent:
if child.tag == tag:
for subchild in child:
- if subchild.tag == subtag:
- if subchild.text == subtagval:
- q = child
+ if (subchild.tag == subtag) and (
+ subchild.text == subtagval
+ ):
+ q = child
return q
diff --git a/ogs6py/classes/curves.py b/ogs6py/classes/curves.py
index c3b3eec..32d676b 100644
--- a/ogs6py/classes/curves.py
+++ b/ogs6py/classes/curves.py
@@ -1,24 +1,29 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class Curves(build_tree.BuildTree):
"""
Class to create the curve section of the project file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
self.curves = self.populate_tree(self.root, "curves", overwrite=True)
- def add_curve(self, **args):
+ def add_curve(self, **args: Any) -> None:
"""
Adds a new curve.
@@ -29,23 +34,28 @@ def add_curve(self, **args):
values : `list`
"""
if "name" not in args:
- raise KeyError("No curve name given.")
+ msg = "No curve name given."
+ raise KeyError(msg)
if "coords" not in args:
- raise KeyError("No coordinates given.")
+ msg = "No coordinates given."
+ raise KeyError(msg)
if "values" not in args:
- raise KeyError("No values given.")
+ msg = "No values given."
+ raise KeyError(msg)
if len(args["coords"]) != len(args["values"]):
- raise ValueError("Number of time coordinate points differs from number of values")
+ msg = """Number of time coordinate points differs \
+ from number of values"""
+ raise ValueError(msg)
curve = self.populate_tree(self.curves, "curve")
- self.populate_tree(curve, "name", args['name'])
+ self.populate_tree(curve, "name", args["name"])
coord_str = ""
value_str = ""
for i, coord in enumerate(args["coords"]):
- if i < (len(args["coords"])-1):
+ if i < (len(args["coords"]) - 1):
coord_str = coord_str + str(coord) + " "
value_str = value_str + str(args["values"][i]) + " "
- if i == (len(args["coords"])-1):
+ if i == (len(args["coords"]) - 1):
coord_str = coord_str + str(coord)
value_str = value_str + str(args["values"][i])
- self.populate_tree(curve, 'coords', text=coord_str)
- self.populate_tree(curve, 'values', text=value_str)
+ self.populate_tree(curve, "coords", text=coord_str)
+ self.populate_tree(curve, "values", text=value_str)
diff --git a/ogs6py/classes/display.py b/ogs6py/classes/display.py
index f7d5135..c34954a 100644
--- a/ogs6py/classes/display.py
+++ b/ogs6py/classes/display.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
@@ -6,48 +5,102 @@
http://www.opengeosys.org/project/license
"""
+from contextlib import suppress
+
+from lxml import etree as ET
+
try:
- from IPython.display import display, Markdown, Latex
+ from IPython.display import Markdown, display
+
verbose = True
except ImportError:
verbose = False
+
# pylint: disable=C0103, R0902, R0914, R0913
class Display:
- """ helper class to create a nested dictionary
+ """helper class to create a nested dictionary
representing the xml structure
"""
- def __init__(self,tree):
+
+ def __init__(self, tree: ET.ElementTree):
if verbose is True:
- display(Markdown('## OpenGeoSys project file'))
- display(Markdown('### Main Info'))
- display(Markdown(f"**Process name:** {tree.find('./processes/process/name').text}"))
- display(Markdown(f"**Process type:** {tree.find('./processes/process/type').text}"))
- t_end = float(tree.find('./time_loop/processes/process/time_stepping/t_end').text)
- t_init = float(tree.find('./time_loop/processes/process/time_stepping/t_initial').text)
- display(Markdown(f"**Simulation time:** {t_end-t_init}"))
- proc_vars = tree.findall("./process_variables/process_variable")
- display(Markdown(f"**Output prefix:** {tree.find('./time_loop/output/prefix').text}"))
- display(Markdown('### Boundary conditions'))
- for var in proc_vars:
- proc_var_entries = var.getchildren()
- for entry in proc_var_entries:
- if entry.tag == "name":
- display(Markdown(f"**Process Variable:** {entry.text}"))
- if entry.tag == "initial_condition":
- display(Markdown(f" - **Initial Condition:** {entry.text}"))
- if entry.tag == "order":
- display(Markdown(f" - **Order:** {entry.text}"))
- if entry.tag == "boundary_conditions":
- bcs = entry.getchildren()
- for bc in bcs:
- bc_entries = bc.getchildren()
- for subentry in bc_entries:
- if subentry.tag == "type":
- display(Markdown(f" - **Type:** {subentry.text}"))
- if subentry.tag == "mesh":
- display(Markdown(f" - **Mesh:** {subentry.text}"))
- if subentry.tag == "geometrical_set":
- display(Markdown(f" - **Geometrical Set:** {subentry.text}"))
- if subentry.tag == "geometry":
- display(Markdown(f" - **Geometry:** {subentry.text}"))
+ display(Markdown("## OpenGeoSys project file"))
+ display(Markdown("### Main Info"))
+ with suppress(AttributeError):
+ display(
+ Markdown(
+ f"**Process name:** {tree.find('./processes/process/name').text}"
+ )
+ )
+ with suppress(AttributeError):
+ display(
+ Markdown(
+ f"**Process type:** {tree.find('./processes/process/type').text}"
+ )
+ )
+ with suppress(AttributeError):
+ t_end = float(
+ tree.find(
+ "./time_loop/processes/process/time_stepping/t_end"
+ ).text
+ )
+ t_init = float(
+ tree.find(
+ "./time_loop/processes/process/time_stepping/t_initial"
+ ).text
+ )
+ display(Markdown(f"**Simulation time:** {t_end-t_init}"))
+ with suppress(AttributeError):
+ proc_vars = tree.findall("./process_variables/process_variable")
+ with suppress(AttributeError):
+ display(
+ Markdown(
+ f"**Output prefix:** {tree.find('./time_loop/output/prefix').text}"
+ )
+ )
+ display(Markdown("### Boundary conditions"))
+ for var in proc_vars:
+ proc_var_entries = var.getchildren()
+ for entry in proc_var_entries:
+ if entry.tag == "name":
+ display(
+ Markdown(f"**Process Variable:** {entry.text}")
+ )
+ if entry.tag == "initial_condition":
+ display(
+ Markdown(
+ f" - **Initial Condition:** {entry.text}"
+ )
+ )
+ if entry.tag == "order":
+ display(Markdown(f" - **Order:** {entry.text}"))
+ if entry.tag == "boundary_conditions":
+ bcs = entry.getchildren()
+ for bc in bcs:
+ bc_entries = bc.getchildren()
+ for subentry in bc_entries:
+ if subentry.tag == "type":
+ display(
+ Markdown(
+ f" - **Type:** {subentry.text}"
+ )
+ )
+ if subentry.tag == "mesh":
+ display(
+ Markdown(
+ f" - **Mesh:** {subentry.text}"
+ )
+ )
+ if subentry.tag == "geometrical_set":
+ display(
+ Markdown(
+ f" - **Geometrical Set:** {subentry.text}"
+ )
+ )
+ if subentry.tag == "geometry":
+ display(
+ Markdown(
+ f" - **Geometry:** {subentry.text}"
+ )
+ )
diff --git a/ogs6py/classes/geo.py b/ogs6py/classes/geo.py
index 0dac5dc..25f8158 100644
--- a/ogs6py/classes/geo.py
+++ b/ogs6py/classes/geo.py
@@ -1,24 +1,27 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class Geo(build_tree.BuildTree):
"""
Class containing the geometry file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
self.populate_tree(self.root, "geometry", overwrite=True)
- def add_geometry(self, filename):
+ def add_geometry(self, filename: str) -> None:
"""
Adds a geometry file.
diff --git a/ogs6py/classes/linsolvers.py b/ogs6py/classes/linsolvers.py
index 3c4c987..243cb60 100644
--- a/ogs6py/classes/linsolvers.py
+++ b/ogs6py/classes/linsolvers.py
@@ -1,80 +1,126 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class LinSolvers(build_tree.BuildTree):
"""
Class for defining a linear solvers in the project file"
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.lss = self.populate_tree(self.root, 'linear_solvers', overwrite=True)
+ self.lss = self.populate_tree(
+ self.root, "linear_solvers", overwrite=True
+ )
- def add_lin_solver(self, **args):
+ def add_lin_solver(self, **args: Any) -> None:
"""
Adds a linear solver
Parameters
----------
name : `str`
+ linear solver name
kind : `str`
- one of `petsc`, `eigen` or `lis`
+ one of `petsc`, `eigen` or `lis`
solver_type : `str`
+ Eigen solver type
precon_type : `str`, optional
+ Eigen preconditioner type
max_iteration_step : `int`, optional
+ max. iteration step
scaling : `str`, optional
- 1 or 0
+ scaling of diagonal
error_tolerance : `float`
+ error tolerance
prefix : `str`, optional
- required for petsc solver
- parameters : `str` for petsc only
+ prefix for petsc solver
+ parameters : `str`
+ petsc parameter configuration
lis : `str` for lis only
+ lis parameter configuration
"""
self._convertargs(args)
if "name" not in args:
- raise KeyError("You need to provide a name for the linear solver.")
- ls = self.populate_tree(self.lss, 'linear_solver', overwrite=True)
- self.populate_tree(ls, 'name', text=args['name'], overwrite=True)
+ msg = "You need to provide a name for the linear solver."
+ raise KeyError(msg)
+ ls = self.populate_tree(self.lss, "linear_solver", overwrite=True)
+ self.populate_tree(ls, "name", text=args["name"], overwrite=True)
if "kind" not in args:
- raise KeyError("No kind given. Please specify the linear \
- solver library (e.g.: eigen, petsc, lis).")
- if args['kind'] == "eigen":
- eigen = self.populate_tree(ls, 'eigen', overwrite=True)
- self.populate_tree(eigen, 'solver_type', text=args['solver_type'], overwrite=True)
+ msg = """No kind given. Please specify the linear \
+ solver library (e.g.: eigen, petsc, lis)."""
+
+ raise KeyError(msg)
+ if args["kind"] == "eigen":
+ eigen = self.populate_tree(ls, "eigen", overwrite=True)
+ self.populate_tree(
+ eigen, "solver_type", text=args["solver_type"], overwrite=True
+ )
if "precon_type" in args:
- self.populate_tree(eigen, 'precon_type', text=args['precon_type'], overwrite=True)
+ self.populate_tree(
+ eigen,
+ "precon_type",
+ text=args["precon_type"],
+ overwrite=True,
+ )
if "max_iteration_step" in args:
- self.populate_tree(eigen, 'max_iteration_step', text=args['max_iteration_step'], overwrite=True)
+ self.populate_tree(
+ eigen,
+ "max_iteration_step",
+ text=args["max_iteration_step"],
+ overwrite=True,
+ )
if "error_tolerance" in args:
- self.populate_tree(eigen, 'error_tolerance', text=args['error_tolerance'], overwrite=True)
+ self.populate_tree(
+ eigen,
+ "error_tolerance",
+ text=args["error_tolerance"],
+ overwrite=True,
+ )
if "scaling" in args:
- self.populate_tree(eigen, 'scaling', text=args['scaling'], overwrite=True)
- elif args['kind'] == "lis":
+ self.populate_tree(
+ eigen, "scaling", text=args["scaling"], overwrite=True
+ )
+ elif args["kind"] == "lis":
if "lis" in args:
lis_string = args["lis"]
else:
- lis_string = (f"-i {args['solver_type']} -p {args['precon_type']}"
+ lis_string = (
+ f"-i {args['solver_type']} -p {args['precon_type']}"
f" -tol {args['error_tolerance']}"
- f" -maxiter {args['max_iteration_step']}")
- self.populate_tree(ls, 'lis', text=lis_string, overwrite=True)
- elif args['kind'] == "petsc":
- petsc = self.populate_tree(ls, 'petsc', overwrite=True)
+ f" -maxiter {args['max_iteration_step']}"
+ )
+ self.populate_tree(ls, "lis", text=lis_string, overwrite=True)
+ elif args["kind"] == "petsc":
+ petsc = self.populate_tree(ls, "petsc", overwrite=True)
prefix = ""
if "prefix" in args:
- self.populate_tree(petsc, 'prefix', args['prefix'], overwrite=True)
- prefix = args['prefix']
+ self.populate_tree(
+ petsc, "prefix", args["prefix"], overwrite=True
+ )
+ prefix = args["prefix"]
if "parameters" in args:
- self.populate_tree(petsc, 'parameters', args['parameters'], overwrite=True)
+ self.populate_tree(
+ petsc, "parameters", args["parameters"], overwrite=True
+ )
else:
- petsc_string = (f"-{prefix}_ksp_type {args['solver_type']} -{prefix}_pc_type"
+ petsc_string = (
+ f"-{prefix}_ksp_type {args['solver_type']} -{prefix}_pc_type"
f" {args['precon_type']} -{prefix}_ksp_rtol {args['error_tolerance']}"
- f" -{prefix}_ksp_max_it {args['max_iteration_step']}")
- self.populate_tree(petsc, 'parameters', petsc_string, overwrite=True)
+ f" -{prefix}_ksp_max_it {args['max_iteration_step']}"
+ )
+ self.populate_tree(
+ petsc, "parameters", petsc_string, overwrite=True
+ )
diff --git a/ogs6py/classes/local_coordinate_system.py b/ogs6py/classes/local_coordinate_system.py
index 10853a9..a96af5d 100644
--- a/ogs6py/classes/local_coordinate_system.py
+++ b/ogs6py/classes/local_coordinate_system.py
@@ -1,24 +1,31 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class LocalCoordinateSystem(build_tree.BuildTree):
"""
Class for defining a local coordinate system in the project file"
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.lcs = None
+ self.lcs = self.populate_tree(
+ self.root, "local_coordinate_system", overwrite=True
+ )
- def add_basis_vec(self, **args):
+ def add_basis_vec(self, **args: Any) -> None:
"""
Adds a basis
@@ -31,12 +38,32 @@ def add_basis_vec(self, **args):
basis_vector_2 : `str`
name of the parameter containing the basis vector
"""
- self._convertargs(args)
- self.lcs = self.populate_tree(self.root, "local_coordinate_system", overwrite=True)
if "basis_vector_0" not in args:
- raise KeyError("no vector given")
- self.populate_tree(self.lcs, "basis_vector_0", text=args["basis_vector_0"])
+ msg = "No vector given."
+ raise KeyError(msg)
+ if args["basis_vector_0"] is None:
+ self.populate_tree(
+ self.lcs, "basis_vector_0", attr={"implicit": "true"}
+ )
+ else:
+ self.populate_tree(
+ self.lcs, "basis_vector_0", text=args["basis_vector_0"]
+ )
if "basis_vector_1" in args:
- self.populate_tree(self.lcs, "basis_vector_1", text=args["basis_vector_1"])
+ if args["basis_vector_1"] is None:
+ self.populate_tree(
+ self.lcs, "basis_vector_1", attr={"implicit": "true"}
+ )
+ else:
+ self.populate_tree(
+ self.lcs, "basis_vector_1", text=args["basis_vector_1"]
+ )
if "basis_vector_2" in args:
- self.populate_tree(self.lcs, "basis_vector_2", text=args["basis_vector_2"])
+ if args["basis_vector_2"] is None:
+ self.populate_tree(
+ self.lcs, "basis_vector_2", attr={"implicit": "true"}
+ )
+ else:
+ self.populate_tree(
+ self.lcs, "basis_vector_2", text=args["basis_vector_2"]
+ )
diff --git a/ogs6py/classes/media.py b/ogs6py/classes/media.py
index 2d15a00..948ad9e 100644
--- a/ogs6py/classes/media.py
+++ b/ogs6py/classes/media.py
@@ -1,183 +1,260 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class Media(build_tree.BuildTree):
"""
Class for defining a media material properties."
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
self.media = self.populate_tree(self.root, "media", overwrite=True)
- self.properties = {"AverageMolarMass": [],
+ self.properties: dict[str, list[str]] = {
+ "AverageMolarMass": [],
"BishopsSaturationCutoff": ["cutoff_value"],
"BishopsPowerLaw": ["exponent"],
- "CapillaryPressureRegularizedVanGenuchten": ["exponent",
- "p_b",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "CapillaryPressureVanGenuchten": ["exponent",
- "maximum_capillary_pressure"
- "p_b",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "ClausiusClapeyron": ["critical_pressure",
- "critical_temperature",
- "reference_pressure",
- "reference_temperature",
- "triple_pressure",
- "triple_temperature"],
+ "CapillaryPressureRegularizedVanGenuchten": [
+ "exponent",
+ "p_b",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "CapillaryPressureVanGenuchten": [
+ "exponent",
+ "maximum_capillary_pressurep_b",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "ClausiusClapeyron": [
+ "critical_pressure",
+ "critical_temperature",
+ "reference_pressure",
+ "reference_temperature",
+ "triple_pressure",
+ "triple_temperature",
+ ],
"Constant": ["value"],
- "Curve" : ["curve", "independent_variable"],
+ "Curve": ["curve", "independent_variable"],
"DupuitPermeability": ["parameter_name"],
"EffectiveThermalConductivityPorosityMixing": [],
- "EmbeddedFracturePermeability": ["intrinsic_permeability",
- "initial_aperture",
- "mean_frac_distance",
- "threshold_strain",
- "fracture_normal",
- "fracture_rotation_xy",
- "fracture_rotation_yz"],
+ "EmbeddedFracturePermeability": [
+ "intrinsic_permeability",
+ "initial_aperture",
+ "mean_frac_distance",
+ "threshold_strain",
+ "fracture_normal",
+ "fracture_rotation_xy",
+ "fracture_rotation_yz",
+ ],
"Function": ["value"],
- "Exponential": ["offset","reference_value"],
- "GasPressureDependentPermeability": ["initial_permeability",
- "a1", "a2",
- "pressure_threshold",
- "minimum_permeability",
- "maximum_permeability"],
+ "Exponential": ["offset", "reference_value"],
+ "GasPressureDependentPermeability": [
+ "initial_permeability",
+ "a1",
+ "a2",
+ "pressure_threshold",
+ "minimum_permeability",
+ "maximum_permeability",
+ ],
"IdealGasLaw": [],
"IdealGasLawBinaryMixture": [],
"KozenyCarmanModel": ["intitial_permeability", "initial_prosity"],
"Linear": ["reference_value"],
- "LinearSaturationSwellingStress" : ["coefficient", "reference_saturation"],
- "LinearWaterVapourLatentHeat" : [],
- "OrthotropicEmbeddedFracturePermeability": ["intrinsic_permeability",
- "mean_frac_distances",
- "threshold_strains",
- "fracture_normals",
- "fracture_rotation_xy",
- "fracture_rotation_yz",
- "jacobian_factor"],
+ "LinearSaturationSwellingStress": [
+ "coefficient",
+ "reference_saturation",
+ ],
+ "LinearWaterVapourLatentHeat": [],
+ "OrthotropicEmbeddedFracturePermeability": [
+ "intrinsic_permeability",
+ "mean_frac_distances",
+ "threshold_strains",
+ "fracture_normals",
+ "fracture_rotation_xy",
+ "fracture_rotation_yz",
+ "jacobian_factor",
+ ],
"Parameter": ["parameter_name"],
- "PermeabilityMohrCoulombFailureIndexModel": ["cohesion",
- "fitting_factor",
- "friction_angle",
- "initial_ppermeability",
- "maximum_permeability",
- "reference_permeability",
- "tensile_strength_parameter"],
- "PermeabilityOrthotropicPowerLaw": ["exponents",
- "intrinsic_permeabilities"],
- "PorosityFromMassBalance": ["initial_porosity",
- "maximal_porosity",
- "minimal_porosity"],
- "RelPermBrooksCorey": ["lambda",
- "min_relative_permeability"
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "RelPermBrooksCoreyNonwettingPhase": ["lambda",
- "min_relative_permeability"
- "residual_gas_saturation",
- "residual_liquid_saturation"],
+ "PermeabilityMohrCoulombFailureIndexModel": [
+ "cohesion",
+ "fitting_factor",
+ "friction_angle",
+ "initial_ppermeability",
+ "maximum_permeability",
+ "reference_permeability",
+ "tensile_strength_parameter",
+ ],
+ "PermeabilityOrthotropicPowerLaw": [
+ "exponents",
+ "intrinsic_permeabilities",
+ ],
+ "PorosityFromMassBalance": [
+ "initial_porosity",
+ "maximal_porosity",
+ "minimal_porosity",
+ ],
+ "RelPermBrooksCorey": [
+ "lambda",
+ "min_relative_permeabilityresidual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "RelPermBrooksCoreyNonwettingPhase": [
+ "lambda",
+ "min_relative_permeabilityresidual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
"RelPermLiakopoulos": [],
- "RelativePermeabilityNonWettingVanGenuchten": ["exponent",
- "minimum_relative_permeability",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "RelativePermeabilityUdell": ["min_relative_permeability",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "RelativePermeabilityUdellNonwettingPhase": ["min_relative_permeability",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "RelativePermeabilityVanGenuchten": ["exponent",
- "minimum_relative_permeability_liquid",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "SaturationBrooksCorey": ["entry_pressure",
- "lambda",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "SaturationDependentSwelling": ["exponents",
- "lower_saturation_limit",
- "swelling_pressures",
- "upper_saturation_limit"],
- "SaturationDependentThermalConductivity": ["dry","wet"],
- "SaturationExponential": ["exponent",
- "maximum_capillary_pressure",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
+ "RelativePermeabilityNonWettingVanGenuchten": [
+ "exponent",
+ "minimum_relative_permeability",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "RelativePermeabilityUdell": [
+ "min_relative_permeability",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "RelativePermeabilityUdellNonwettingPhase": [
+ "min_relative_permeability",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "RelativePermeabilityVanGenuchten": [
+ "exponent",
+ "minimum_relative_permeability_liquid",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "SaturationBrooksCorey": [
+ "entry_pressure",
+ "lambda",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "SaturationDependentSwelling": [
+ "exponents",
+ "lower_saturation_limit",
+ "swelling_pressures",
+ "upper_saturation_limit",
+ ],
+ "SaturationDependentThermalConductivity": ["dry", "wet"],
+ "SaturationExponential": [
+ "exponent",
+ "maximum_capillary_pressure",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
"SaturationLiakopoulos": [],
- "SaturationWeightedThermalConductivity": ["mean_type", "dry_thermal_conductivity","wet_thermal_conductivity"],
- "SaturationVanGenuchten": ["exponent",
- "p_b",
- "residual_gas_saturation",
- "residual_liquid_saturation"],
- "SoilThermalConductivitySomerton": ["dry_thermal_conductivity",
- "wet_thermal_conductivity"],
- "StrainDependentPermeability": ["initial_permeability",
- "b1", "b2", "b3",
- "minimum_permeability",
- "maximum_permeability"],
- "TemperatureDependentDiffusion": ["activation_energy",
- "reference_diffusion",
- "reference_temperature"],
- "TransportPorosityFromMassBalance": ["initial_porosity",
- "maximal_porosity",
- "minimal_porosity"],
+ "SaturationWeightedThermalConductivity": [
+ "mean_type",
+ "dry_thermal_conductivity",
+ "wet_thermal_conductivity",
+ ],
+ "SaturationVanGenuchten": [
+ "exponent",
+ "p_b",
+ "residual_gas_saturation",
+ "residual_liquid_saturation",
+ ],
+ "SoilThermalConductivitySomerton": [
+ "dry_thermal_conductivity",
+ "wet_thermal_conductivity",
+ ],
+ "StrainDependentPermeability": [
+ "initial_permeability",
+ "b1",
+ "b2",
+ "b3",
+ "minimum_permeability",
+ "maximum_permeability",
+ ],
+ "TemperatureDependentDiffusion": [
+ "activation_energy",
+ "reference_diffusion",
+ "reference_temperature",
+ ],
+ "TransportPorosityFromMassBalance": [
+ "initial_porosity",
+ "maximal_porosity",
+ "minimal_porosity",
+ ],
"VapourDiffusionFEBEX": ["tortuosity"],
"VapourDiffusionPMQ": [],
- "VermaPruessModel": ["critical_porosity",
- "exponent",
- "initial_permeability",
- "initial_porosity"],
+ "VermaPruessModel": [
+ "critical_porosity",
+ "exponent",
+ "initial_permeability",
+ "initial_porosity",
+ ],
"WaterVapourDensity": [],
"WaterDensityIAPWSIF97Region1": [],
- "WaterVapourLatentHeatWithCriticalTemperature": []
- }
+ "WaterVapourLatentHeatWithCriticalTemperature": [],
+ }
- def _generate_generic_property(self, property_, args):
+ def _generate_generic_property(
+ self, property_: ET.Element, args: dict[str, Any]
+ ) -> None:
for parameter in self.properties[args["type"]]:
self.populate_tree(property_, parameter, text=args[parameter])
- def _generate_linear_property(self, property_, args):
+ def _generate_linear_property(
+ self, property_: ET.Element, args: dict[str, Any]
+ ) -> None:
for parameter in self.properties[args["type"]]:
self.populate_tree(property_, parameter, text=args[parameter])
for var, param in args["independent_variables"].items():
- ind_var = self.populate_tree(property_, 'independent_variable')
+ ind_var = self.populate_tree(property_, "independent_variable")
self.populate_tree(ind_var, "variable_name", text=var)
- attributes = ['reference_condition','slope']
+ attributes = ["reference_condition", "slope"]
for attrib in attributes:
self.populate_tree(ind_var, attrib, text=str(param[attrib]))
- def _generate_function_property(self, property_, args):
+ def _generate_function_property(
+ self, property_: ET.Element, args: dict[str, Any]
+ ) -> None:
for parameter in self.properties[args["type"]]:
- value = self.populate_tree(property_, parameter, text=args[parameter])
+ value = self.populate_tree(
+ property_, parameter, text=args[parameter]
+ )
self.populate_tree(value, "expression", text=args["expression"])
for dvar in args["dvalues"]:
dvalue = self.populate_tree(property_, "dvalue")
self.populate_tree(dvalue, "variable_name", text=dvar)
- self.populate_tree(dvalue, "expression", text=args["dvalues"][dvar]["expression"])
+ self.populate_tree(
+ dvalue, "expression", text=args["dvalues"][dvar]["expression"]
+ )
- def _generate_exponential_property(self, property_, args):
+ def _generate_exponential_property(
+ self, property_: ET.Element, args: dict[str, Any]
+ ) -> None:
for parameter in self.properties[args["type"]]:
self.populate_tree(property_, parameter, text=args[parameter])
- exponent = self.populate_tree(property_, 'exponent')
- self.populate_tree(exponent, "variable_name", text=args["exponent"]["variable_name"])
- attributes = ['reference_condition','factor']
+ exponent = self.populate_tree(property_, "exponent")
+ self.populate_tree(
+ exponent, "variable_name", text=args["exponent"]["variable_name"]
+ )
+ attributes = ["reference_condition", "factor"]
for attrib in attributes:
- self.populate_tree(exponent, attrib, text=str(args["exponent"][attrib]))
+ self.populate_tree(
+ exponent, attrib, text=str(args["exponent"][attrib])
+ )
- def add_property(self, **args):
+ def add_property(self, **args: Any) -> None:
"""
Adds a property to medium/phase
@@ -204,19 +281,25 @@ def add_property(self, **args):
if entry.get("id") == args["medium_id"]:
medium = entry
if medium is None:
- medium = self.populate_tree(self.media, "medium", attr={"id": args["medium_id"]})
+ medium = self.populate_tree(
+ self.media, "medium", attr={"id": args["medium_id"]}
+ )
if "phase_type" in args:
phases = self.get_child_tag(medium, "phases")
if phases is None:
phases = self.populate_tree(medium, "phases")
- phase = self.get_child_tag_for_type(phases, "phase", args['phase_type'])
+ phase = self.get_child_tag_for_type(
+ phases, "phase", args["phase_type"]
+ )
if phase is None:
phase = self.populate_tree(phases, "phase")
- self.populate_tree(phase, "type", text=args['phase_type'])
+ self.populate_tree(phase, "type", text=args["phase_type"])
if "component_name" in args:
components = self.populate_tree(phase, "components")
component = self.populate_tree(components, "component")
- self.populate_tree(component, "name", text=args['component_name'])
+ self.populate_tree(
+ component, "name", text=args["component_name"]
+ )
properties = self.populate_tree(component, "properties")
else:
properties = self.populate_tree(phase, "properties")
@@ -225,12 +308,22 @@ def add_property(self, **args):
components = self.get_child_tag(phase, "components")
if components is None:
components = self.populate_tree(phase, "components")
- component = self.get_child_tag_for_type(components, "component",
- args['component_name'], subtag="name")
+ component = self.get_child_tag_for_type(
+ components,
+ "component",
+ args["component_name"],
+ subtag="name",
+ )
if component is None:
- component = self.populate_tree(components, "component")
- self.populate_tree(component, "name", text=args['component_name'])
- properties = self.populate_tree(component, "properties", overwrite=True)
+ component = self.populate_tree(
+ components, "component"
+ )
+ self.populate_tree(
+ component, "name", text=args["component_name"]
+ )
+ properties = self.populate_tree(
+ component, "properties", overwrite=True
+ )
else:
properties = self.get_child_tag(phase, "properties")
else:
@@ -243,17 +336,21 @@ def add_property(self, **args):
for param in base_property_param:
self.populate_tree(property_, param, text=args[param])
try:
- if args['type'] == "Linear":
+ if args["type"] == "Linear":
self._generate_linear_property(property_, args)
- elif args['type'] == "Exponential":
+ elif args["type"] == "Exponential":
self._generate_exponential_property(property_, args)
- elif args['type'] == "Function":
+ elif args["type"] == "Function":
self._generate_function_property(property_, args)
else:
self._generate_generic_property(property_, args)
except KeyError:
print("Material property parameters incomplete for")
if "phase_type" in args:
- print(f"Medium {args['medium_id']}->{args['phase_type']}->{args['name']}[{args['type']}]")
+ print(
+ f"Medium {args['medium_id']}->{args['phase_type']}->{args['name']}[{args['type']}]"
+ )
else:
- print(f"Medium {args['medium_id']}->{args['name']}[{args['type']}]")
+ print(
+ f"Medium {args['medium_id']}->{args['name']}[{args['type']}]"
+ )
diff --git a/ogs6py/classes/mesh.py b/ogs6py/classes/mesh.py
index 81b3c87..82d37c8 100644
--- a/ogs6py/classes/mesh.py
+++ b/ogs6py/classes/mesh.py
@@ -1,19 +1,24 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class Mesh(build_tree.BuildTree):
"""
Class for defining meshes in the project file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
self.geometry = self.root.find("./geometry")
@@ -22,7 +27,9 @@ def __init__(self, tree):
if self.meshes is None:
self.mesh = self.populate_tree(self.root, "mesh", overwrite=True)
- def add_mesh(self, filename, axially_symmetric=None):
+ def add_mesh(
+ self, filename: str, axially_symmetric: Any | None = None
+ ) -> None:
"""
adds a mesh to the project file
@@ -40,27 +47,42 @@ def add_mesh(self, filename, axially_symmetric=None):
elif isinstance(axially_symmetric, str):
attr_dict = {"axially_symmetric": axially_symmetric}
if self.mesh is not None:
- if self.mesh.text == "" or self.mesh.text is None:
- self.populate_tree(self.root, "mesh", text=filename, attr=attr_dict, overwrite=True)
+ if (self.mesh.text == "") or (self.mesh.text is None):
+ self.populate_tree(
+ self.root,
+ "mesh",
+ text=filename,
+ attr=attr_dict,
+ overwrite=True,
+ )
else:
entry = self.mesh.text
attrib = self.mesh.get("axially_symmetric")
- mesh0attr_dict ={}
+ mesh0attr_dict = {}
if isinstance(attrib, str):
mesh0attr_dict = {"axially_symmetric": attrib}
self.mesh.tag = "meshes"
- self.meshes = self.populate_tree(self.root, "meshes", text="", attr={}, overwrite=True)
+ self.meshes = self.populate_tree(
+ self.root, "meshes", text="", attr={}, overwrite=True
+ )
self.mesh = None
if self.geometry is not None:
self.geometry.getparent().remove(self.geometry)
self.geometry = self.root.find("./geometry")
- self.populate_tree(self.meshes, "mesh", text=entry, attr=mesh0attr_dict)
- self.populate_tree(self.meshes, "mesh", text=filename, attr=attr_dict)
+ self.populate_tree(
+ self.meshes, "mesh", text=entry, attr=mesh0attr_dict
+ )
+ self.populate_tree(
+ self.meshes, "mesh", text=filename, attr=attr_dict
+ )
elif self.meshes is not None:
- self.populate_tree(self.meshes, "mesh", text=filename, attr=attr_dict)
+ self.populate_tree(
+ self.meshes, "mesh", text=filename, attr=attr_dict
+ )
self.geometry = self.root.find("./geometry")
if self.geometry is not None:
self.geometry.getparent().remove(self.geometry)
self.geometry = self.root.find("./geometry")
else:
- raise RuntimeError("This should not happpen")
+ msg = "This should not happen"
+ raise RuntimeError(msg)
diff --git a/ogs6py/classes/nonlinsolvers.py b/ogs6py/classes/nonlinsolvers.py
index 73a62ee..cb7f497 100644
--- a/ogs6py/classes/nonlinsolvers.py
+++ b/ogs6py/classes/nonlinsolvers.py
@@ -1,49 +1,64 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class NonLinSolvers(build_tree.BuildTree):
"""
Adds a non-linearsolver section in the project file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.nlss = self.populate_tree(self.root, 'nonlinear_solvers', overwrite=True)
+ self.nlss = self.populate_tree(
+ self.root, "nonlinear_solvers", overwrite=True
+ )
- def add_non_lin_solver(self, **args):
+ def add_non_lin_solver(self, **args: Any) -> None:
"""
add a nonlinear solver.
Parameters
----------
name : `str`
+ name
type : `str`
- one of `Picard` or `Newton`
+ one of `Picard`, `Newton` or `PETScSNES`
max_iter : `int` or `str`
+ maximum iteraterion
linear_solver : `str`
+ linear solver configuration to chose
damping : `float` or `str`
+ damping for newton step
"""
self._convertargs(args)
if "name" not in args:
- raise KeyError("Missing name of the nonlinear solver.")
+ msg = "Missing name of the nonlinear solver."
+ raise KeyError(msg)
if "type" not in args:
- raise KeyError("Please specify the type of the nonlinear solver.")
+ msg = "Please specify the type of the nonlinear solver."
+ raise KeyError(msg)
if "max_iter" not in args:
- raise KeyError("Please provide the maximum number of iterations (max_iter).")
+ msg = "Please provide the maximum number of iterations (max_iter)."
+ raise KeyError(msg)
if "linear_solver" not in args:
- raise KeyError("No linear_solver specified.")
+ msg = "No linear_solver specified."
+ raise KeyError(msg)
nls = self.populate_tree(self.nlss, "nonlinear_solver")
- self.populate_tree(nls, "name", text=args['name'])
- self.populate_tree(nls, "type", text=args['type'])
- self.populate_tree(nls, "max_iter", text=args['max_iter'])
- self.populate_tree(nls, "linear_solver", text=args['linear_solver'])
+ self.populate_tree(nls, "name", text=args["name"])
+ self.populate_tree(nls, "type", text=args["type"])
+ self.populate_tree(nls, "max_iter", text=args["max_iter"])
+ self.populate_tree(nls, "linear_solver", text=args["linear_solver"])
if "damping" in args:
- self.populate_tree(nls, "damping", text=args['damping'])
+ self.populate_tree(nls, "damping", text=args["damping"])
diff --git a/ogs6py/classes/parameters.py b/ogs6py/classes/parameters.py
index 9936c2b..0df24da 100644
--- a/ogs6py/classes/parameters.py
+++ b/ogs6py/classes/parameters.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
@@ -7,18 +6,26 @@
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class Parameters(build_tree.BuildTree):
"""
Class for managing the parameters section of the project file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.parameters = self.populate_tree(self.root, 'parameters', overwrite=True)
+ self.parameters = self.populate_tree(
+ self.root, "parameters", overwrite=True
+ )
- def add_parameter(self, **args):
+ def add_parameter(self, **args: Any) -> None:
"""
Adds a parameter
@@ -39,60 +46,74 @@ def add_parameter(self, **args):
"""
self._convertargs(args)
if "name" not in args:
- raise KeyError("No parameter name given.")
+ msg = "No parameter name given."
+ raise KeyError(msg)
if "type" not in args:
- raise KeyError("Parameter type not given.")
- parameter = self.populate_tree(self.parameters, 'parameter')
- self.populate_tree(parameter, 'name', text=args['name'])
- self.populate_tree(parameter, 'type', text=args['type'])
- #entries = len(self.tree['parameters']['children'])
- #self.tree['parameters']['children'][
+ msg = "Parameter type not given."
+ raise KeyError(msg)
+ parameter = self.populate_tree(self.parameters, "parameter")
+ self.populate_tree(parameter, "name", text=args["name"])
+ self.populate_tree(parameter, "type", text=args["type"])
+ # entries = len(self.tree['parameters']['children'])
+ # self.tree['parameters']['children'][
# 'param' + str(entries)] = self.populate_tree('parameter',
# children={})
- #parameter = self.tree['parameters']['children']['param' +
+ # parameter = self.tree['parameters']['children']['param' +
# str(entries)]
- #parameter['children']['name'] = self.populate_tree(
+ # parameter['children']['name'] = self.populate_tree(
# 'name', text=args['name'], children={})
- #parameter['children']['type'] = self.populate_tree(
+ # parameter['children']['type'] = self.populate_tree(
# 'type', text=args['type'], children={})
if args["type"] == "Constant":
if "value" in args:
- self.populate_tree(parameter, 'value', text=args['value'])
+ self.populate_tree(parameter, "value", text=args["value"])
elif "values" in args:
- self.populate_tree(parameter, 'values', text=args['values'])
+ self.populate_tree(parameter, "values", text=args["values"])
elif args["type"] == "MeshElement" or args["type"] == "MeshNode":
- if 'mesh' in args:
- self.populate_tree(parameter, 'mesh', text=args['mesh'])
- self.populate_tree(parameter, 'field_name', text=args['field_name'])
+ if "mesh" in args:
+ self.populate_tree(parameter, "mesh", text=args["mesh"])
+ self.populate_tree(parameter, "field_name", text=args["field_name"])
elif args["type"] == "Function":
if "mesh" in args:
- self.populate_tree(parameter, 'mesh', text=args['mesh'])
- if isinstance(args['expression'], str) is True:
- self.populate_tree(parameter, 'expression', text=args['expression'])
- elif isinstance(args['expression'], list) is True:
- for i, entry in enumerate(args['expression']):
- self.populate_tree(parameter, 'expression', text=entry)
+ self.populate_tree(parameter, "mesh", text=args["mesh"])
+ if isinstance(args["expression"], str) is True:
+ self.populate_tree(
+ parameter, "expression", text=args["expression"]
+ )
+ elif isinstance(args["expression"], list) is True:
+ for entry in args["expression"]:
+ self.populate_tree(parameter, "expression", text=entry)
elif args["type"] == "CurveScaled":
if "curve" in args:
- self.populate_tree(parameter, 'curve', text=args['curve'])
+ self.populate_tree(parameter, "curve", text=args["curve"])
if "parameter" in args:
- self.populate_tree(parameter, 'parameter', text=args['parameter'])
+ self.populate_tree(
+ parameter, "parameter", text=args["parameter"]
+ )
elif args["type"] == "TimeDependentHeterogeneousParameter":
if "time" not in args:
- raise KeyError("time missing.")
+ msg = "time missing."
+ raise KeyError(msg)
if "parameter_name" not in args:
- raise KeyError("Parameter name missing.")
- if not len(args["time"]) == len(args["parameter_name"]):
- raise KeyError("parameter_name and time lists have different length.")
- time_series = self.populate_tree(parameter, 'time_series')
+ msg = "Parameter name missing."
+ raise KeyError(msg)
+ if len(args["time"]) != len(args["parameter_name"]):
+ msg = "parameter_name and time lists have different length."
+ raise KeyError(msg)
+ time_series = self.populate_tree(parameter, "time_series")
for i, _ in enumerate(args["parameter_name"]):
- ts_pair = self.populate_tree(time_series, 'pair')
- self.populate_tree(ts_pair, 'time', text=args['time'][i])
- self.populate_tree(ts_pair, 'time', text=args['parameter_name'][i])
+ ts_pair = self.populate_tree(time_series, "pair")
+ self.populate_tree(ts_pair, "time", text=str(args["time"][i]))
+ self.populate_tree(
+ ts_pair, "parameter_name", text=args["parameter_name"][i]
+ )
else:
- raise KeyError("Parameter type not supported (yet).")
- if "use_local_coordinate_system" in args:
- if (args["use_local_coordinate_system"] == "true") or (
- args["use_local_coordinate_system"] is True):
- self.populate_tree(parameter,
- 'use_local_coordinate_system', text='true')
+ msg = "Parameter type not supported (yet)."
+ raise KeyError(msg)
+ if ("use_local_coordinate_system" in args) and (
+ (args["use_local_coordinate_system"] == "true")
+ or (args["use_local_coordinate_system"] is True)
+ ):
+ self.populate_tree(
+ parameter, "use_local_coordinate_system", text="true"
+ )
diff --git a/ogs6py/classes/processes.py b/ogs6py/classes/processes.py
index 33fe976..0603e23 100644
--- a/ogs6py/classes/processes.py
+++ b/ogs6py/classes/processes.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
@@ -7,27 +6,37 @@
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class Processes(build_tree.BuildTree):
"""
Class for managing the processes section in the project file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.processes = self.populate_tree(self.root, "processes", overwrite=True)
- self.process = self.populate_tree(self.processes, "process", overwrite=True)
+ self.processes = self.populate_tree(
+ self.root, "processes", overwrite=True
+ )
+ self.process = self.populate_tree(
+ self.processes, "process", overwrite=True
+ )
self.procvars = None
- self.procvar = {}
+ self.procvar: dict[str, ET.Element] = {}
self.secondvars = None
- self.secondvar = {}
- self.process_baseentries = {}
- self.constitutive_relation = {}
+ self.process_baseentries: dict[str, ET.Element] = {}
self.borehole_heat_exchangers = None
- self.borehole_heat_exchanger = []
+ self.borehole_heat_exchanger: list[ET.Element] = []
- def add_process_variable(self, process_variable="", process_variable_name=""):
+ def add_process_variable(
+ self, process_variable: str = "", process_variable_name: str = ""
+ ) -> None:
"""
Adds a process variable.
@@ -36,14 +45,20 @@ def add_process_variable(self, process_variable="", process_variable_name=""):
process_variable : `str`
process_variable_name : `str`
"""
- self.procvars = self.populate_tree(self.process, "process_variables", overwrite=True)
+ self.procvars = self.populate_tree(
+ self.process, "process_variables", overwrite=True
+ )
if process_variable != "":
if process_variable_name == "":
- raise KeyError("process_variable_name missing.")
- self.procvar[process_variable] = self.populate_tree(self.procvars,
- process_variable, text=process_variable_name)
+ msg = "process_variable_name missing."
+ raise KeyError(msg)
+ self.procvar[process_variable] = self.populate_tree(
+ self.procvars, process_variable, text=process_variable_name
+ )
- def add_secondary_variable(self, internal_name, output_name):
+ def add_secondary_variable(
+ self, internal_name: str, output_name: str
+ ) -> None:
"""
Adds a secondary variable.
@@ -52,13 +67,17 @@ def add_secondary_variable(self, internal_name, output_name):
internal_variable : `str`
output_name : `str`
"""
- self.secondvars = self.populate_tree(self.process, "secondary_variables", overwrite=True)
+ self.secondvars = self.populate_tree(
+ self.process, "secondary_variables", overwrite=True
+ )
attrs = {"internal_name": internal_name, "output_name": output_name}
self.populate_tree(self.secondvars, "secondary_variable", attr=attrs)
- def set_process(self, **args):
+ def set_process(self, **args: Any) -> None:
"""
Set basic process properties.
+ any pair tag="value" translates to
+ value in process section
Parameters
----------
@@ -66,43 +85,72 @@ def set_process(self, **args):
type : `str`
integration_order : `str`
darcy_gravity/specific_body_force : `list` or `tuple`
- holding darcy accelleration as vector
- any pair tag="value" translates to
- value in process section
"""
self._convertargs(args)
if "name" not in args:
- raise KeyError("No process name given.")
+ msg = "No process name given."
+ raise KeyError(msg)
if "type" not in args:
- raise KeyError("type missing.")
+ msg = "type missing."
+ raise KeyError(msg)
if "integration_order" not in args:
- raise KeyError("integration_order missing.")
+ msg = "integration_order missing."
+ raise KeyError(msg)
for key, value in args.items():
if key == "darcy_gravity":
for i, entry in enumerate(args["darcy_gravity"]):
if entry != 0.0:
- self.process_baseentries["darcy_gravity"] = self.populate_tree(
- self.process, "darcy_gravity")
- self.populate_tree(self.process_baseentries["darcy_gravity"],
- "axis_id",text =str(i))
- self.populate_tree(self.process_baseentries["darcy_gravity"],
- "g",text = str(entry))
+ self.process_baseentries[
+ "darcy_gravity"
+ ] = self.populate_tree(
+ self.process, "darcy_gravity", overwrite=True
+ )
+ self.populate_tree(
+ self.process_baseentries["darcy_gravity"],
+ "axis_id",
+ text=str(i),
+ )
+ self.populate_tree(
+ self.process_baseentries["darcy_gravity"],
+ "g",
+ text=str(entry),
+ )
elif key == "specific_body_force":
if isinstance(args["specific_body_force"], list):
- self.populate_tree(self.process, "specific_body_force",
- text=" ".join(str(x) for x in args['specific_body_force']))
+ self.populate_tree(
+ self.process,
+ "specific_body_force",
+ text=" ".join(
+ str(x) for x in args["specific_body_force"]
+ ),
+ overwrite=True,
+ )
else:
- self.populate_tree(self.process, "specific_body_force",
- text=args["specific_body_force"])
+ self.populate_tree(
+ self.process,
+ "specific_body_force",
+ text=args["specific_body_force"],
+ overwrite=True,
+ )
+ elif (key == "coupling_scheme") and (
+ args["type"] in ["HYDRO_MECHANICS"]
+ ):
+ cs = self.populate_tree(
+ self.process, "coupling_scheme", overwrite=True
+ )
+ self.populate_tree(
+ cs, "type", text=args["coupling_scheme"], overwrite=True
+ )
else:
if isinstance(value, str):
- self.populate_tree(self.process, key, text=value)
+ self.populate_tree(
+ self.process, key, text=value, overwrite=True
+ )
else:
- raise RuntimeError(f"{key} is not of type string")
-
+ msg = f"{key} is not of type string"
+ raise RuntimeError(msg)
-
- def set_constitutive_relation(self, **args):
+ def set_constitutive_relation(self, **args: Any) -> None:
"""
Sets constituitive relation
@@ -115,36 +163,48 @@ def set_constitutive_relation(self, **args):
"""
self._convertargs(args)
if "id" in args:
- const_rel = self.populate_tree(self.process, "constitutive_relation", attr={"id": args["id"]})
+ const_rel = self.populate_tree(
+ self.process, "constitutive_relation", attr={"id": args["id"]}
+ )
else:
- const_rel = self.populate_tree(self.process, "constitutive_relation", overwrite=True)
+ const_rel = self.populate_tree(
+ self.process, "constitutive_relation", overwrite=True
+ )
for key, value in args.items():
if key not in ["id"]:
self.populate_tree(const_rel, key, text=value, overwrite=True)
-
- def add_bhe_type(self, bhe_type):
+ def add_bhe_type(self, bhe_type: str) -> None:
"""
Adds a BHE type
"""
self.borehole_heat_exchangers = self.populate_tree(
- self.process, "borehole_heat_exchangers", overwrite=True)
- self.borehole_heat_exchanger.append(self.populate_tree(
- self.borehole_heat_exchangers, "borehole_heat_exchanger"))
- self.populate_tree(self.borehole_heat_exchanger[-1], "type", text = bhe_type)
+ self.process, "borehole_heat_exchangers", overwrite=True
+ )
+ self.borehole_heat_exchanger.append(
+ self.populate_tree(
+ self.borehole_heat_exchangers, "borehole_heat_exchanger"
+ )
+ )
+ self.populate_tree(
+ self.borehole_heat_exchanger[-1], "type", text=bhe_type
+ )
- def add_bhe_component(self, index=0, **args):
+ def add_bhe_component(self, index: int = 0, **args: Any) -> None:
"""
adds a BHE component
"""
self._convertargs(args)
bhe_type = ""
- if 'comp_type' not in args:
- raise KeyError("No BHE component name specified.")
- bhecomponent = self.populate_tree(self.borehole_heat_exchanger[index], args['comp_type'])
+ if "comp_type" not in args:
+ msg = "No BHE component name specified."
+ raise KeyError(msg)
+ bhecomponent = self.populate_tree(
+ self.borehole_heat_exchanger[index], args["comp_type"]
+ )
if bhecomponent.tag == "borehole":
- self.populate_tree(bhecomponent, 'length', text = args['length'])
- self.populate_tree(bhecomponent, 'diameter', text = args['diameter'])
+ self.populate_tree(bhecomponent, "length", text=args["length"])
+ self.populate_tree(bhecomponent, "diameter", text=args["diameter"])
elif bhecomponent.tag == "pipes":
for element in self.borehole_heat_exchanger[index]:
if element.tag == "type":
@@ -156,50 +216,122 @@ def add_bhe_component(self, index=0, **args):
outlet_text = "outer"
inlet = self.populate_tree(bhecomponent, inlet_text)
outlet = self.populate_tree(bhecomponent, outlet_text)
- self.populate_tree(inlet, "diameter", text=args['inlet_diameter'])
- self.populate_tree(inlet, "wall_thickness", text=args['inlet_wall_thickness'])
- self.populate_tree(inlet, "wall_thermal_conductivity", text=args['inlet_wall_thermal_conductivity'])
- self.populate_tree(outlet, "diameter", text=args['outlet_diameter'])
- self.populate_tree(outlet, "wall_thickness", text=args['outlet_wall_thickness'])
- self.populate_tree(outlet, "wall_thermal_conductivity", text=args['outlet_wall_thermal_conductivity'])
- self.populate_tree(bhecomponent, "distance_between_pipes", text=args['distance_between_pipes'])
- self.populate_tree(bhecomponent, "longitudinal_dispersion_length", text=args['longitudinal_dispersion_length'])
+ self.populate_tree(inlet, "diameter", text=args["inlet_diameter"])
+ self.populate_tree(
+ inlet, "wall_thickness", text=args["inlet_wall_thickness"]
+ )
+ self.populate_tree(
+ inlet,
+ "wall_thermal_conductivity",
+ text=args["inlet_wall_thermal_conductivity"],
+ )
+ self.populate_tree(outlet, "diameter", text=args["outlet_diameter"])
+ self.populate_tree(
+ outlet, "wall_thickness", text=args["outlet_wall_thickness"]
+ )
+ self.populate_tree(
+ outlet,
+ "wall_thermal_conductivity",
+ text=args["outlet_wall_thermal_conductivity"],
+ )
+ self.populate_tree(
+ bhecomponent,
+ "distance_between_pipes",
+ text=args["distance_between_pipes"],
+ )
+ self.populate_tree(
+ bhecomponent,
+ "longitudinal_dispersion_length",
+ text=args["longitudinal_dispersion_length"],
+ )
elif bhecomponent.tag == "flow_and_temperature_control":
- self.populate_tree(bhecomponent, "type", text=args['type'])
- if args['type'] == "FixedPowerConstantFlow":
- self.populate_tree(bhecomponent, "power", text=args['power'])
- self.populate_tree(bhecomponent, "flow_rate", text=args['flow_rate'])
- elif args['type'] == "FixedPowerFlowCurve":
- self.populate_tree(bhecomponent, "power", text=args['power'])
- self.populate_tree(bhecomponent, "flow_rate_curve", text=args['flow_rate_curve'])
- elif args['type'] == "PowerCurveConstantFlow":
- self.populate_tree(bhecomponent, "power_curve", text=args['power_curve'])
- self.populate_tree(bhecomponent, "flow_rate", text=args['flow_rate'])
- elif args['type'] == "TemperatureCurveConstantFlow":
- self.populate_tree(bhecomponent, "flow_rate", text=args['flow_rate'])
- self.populate_tree(bhecomponent, "temperature_curve", text=args['temperature_curve'])
- elif args['type'] == "TemperatureCurveFlowCurve":
- self.populate_tree(bhecomponent, "flow_rate_curve", text=args['flow_rate_curve'])
- self.populate_tree(bhecomponent, "temperature_curve", text=args['temperature_curve'])
- elif args['type'] == "PowerCurveFlowCurve":
- self.populate_tree(bhecomponent, "power_curve", text=args['power_curve'])
- self.populate_tree(bhecomponent, "flow_rate_curve", text=args['flow_rate_curve'])
+ self.populate_tree(bhecomponent, "type", text=args["type"])
+ if args["type"] == "FixedPowerConstantFlow":
+ self.populate_tree(bhecomponent, "power", text=args["power"])
+ self.populate_tree(
+ bhecomponent, "flow_rate", text=args["flow_rate"]
+ )
+ elif args["type"] == "FixedPowerFlowCurve":
+ self.populate_tree(bhecomponent, "power", text=args["power"])
+ self.populate_tree(
+ bhecomponent,
+ "flow_rate_curve",
+ text=args["flow_rate_curve"],
+ )
+ elif args["type"] == "PowerCurveConstantFlow":
+ self.populate_tree(
+ bhecomponent, "power_curve", text=args["power_curve"]
+ )
+ self.populate_tree(
+ bhecomponent, "flow_rate", text=args["flow_rate"]
+ )
+ elif args["type"] == "TemperatureCurveConstantFlow":
+ self.populate_tree(
+ bhecomponent, "flow_rate", text=args["flow_rate"]
+ )
+ self.populate_tree(
+ bhecomponent,
+ "temperature_curve",
+ text=args["temperature_curve"],
+ )
+ elif args["type"] == "TemperatureCurveFlowCurve":
+ self.populate_tree(
+ bhecomponent,
+ "flow_rate_curve",
+ text=args["flow_rate_curve"],
+ )
+ self.populate_tree(
+ bhecomponent,
+ "temperature_curve",
+ text=args["temperature_curve"],
+ )
+ elif args["type"] == "PowerCurveFlowCurve":
+ self.populate_tree(
+ bhecomponent, "power_curve", text=args["power_curve"]
+ )
+ self.populate_tree(
+ bhecomponent,
+ "flow_rate_curve",
+ text=args["flow_rate_curve"],
+ )
elif bhecomponent.tag == "grout":
- self.populate_tree(bhecomponent, "density", text=args['density'])
- self.populate_tree(bhecomponent, "porosity", text=args['porosity'])
- self.populate_tree(bhecomponent, "specific_heat_capacity", text=args['specific_heat_capacity'])
- self.populate_tree(bhecomponent, "thermal_conductivity", text=args['thermal_conductivity'])
+ self.populate_tree(bhecomponent, "density", text=args["density"])
+ self.populate_tree(bhecomponent, "porosity", text=args["porosity"])
+ self.populate_tree(
+ bhecomponent,
+ "specific_heat_capacity",
+ text=args["specific_heat_capacity"],
+ )
+ self.populate_tree(
+ bhecomponent,
+ "thermal_conductivity",
+ text=args["thermal_conductivity"],
+ )
elif bhecomponent.tag == "refrigerant":
- self.populate_tree(bhecomponent, "density", text=args['density'])
- self.populate_tree(bhecomponent, "viscosity", text=args['viscosity'])
- self.populate_tree(bhecomponent, "specific_heat_capacity", text=args['specific_heat_capacity'])
- self.populate_tree(bhecomponent, "thermal_conductivity", text=args['thermal_conductivity'])
- self.populate_tree(bhecomponent, "reference_temperature", text=args['reference_temperature'])
+ self.populate_tree(bhecomponent, "density", text=args["density"])
+ self.populate_tree(
+ bhecomponent, "viscosity", text=args["viscosity"]
+ )
+ self.populate_tree(
+ bhecomponent,
+ "specific_heat_capacity",
+ text=args["specific_heat_capacity"],
+ )
+ self.populate_tree(
+ bhecomponent,
+ "thermal_conductivity",
+ text=args["thermal_conductivity"],
+ )
+ self.populate_tree(
+ bhecomponent,
+ "reference_temperature",
+ text=args["reference_temperature"],
+ )
- def add_surfaceflux(self, **args):
+ def add_surfaceflux(self, **args: Any) -> None:
"""
Add SurfaceFlux
@@ -221,9 +353,13 @@ def add_surfaceflux(self, **args):
self._convertargs(args)
if "mesh" not in args:
- raise KeyError("No surface mesh for flux analysis assigned")
+ msg = "No surface mesh for flux analysis assigned"
+ raise KeyError(msg)
if "property_name" not in args:
- raise KeyError("No property name, e.g specific_flux, assigned")
- surfaceflux = self.populate_tree(self.process, "calculatesurfaceflux", overwrite=True)
+ msg = "No property name, e.g specific_flux, assigned"
+ raise KeyError(msg)
+ surfaceflux = self.populate_tree(
+ self.process, "calculatesurfaceflux", overwrite=True
+ )
self.populate_tree(surfaceflux, "mesh", args["mesh"])
self.populate_tree(surfaceflux, "property_name", args["property_name"])
diff --git a/ogs6py/classes/processvars.py b/ogs6py/classes/processvars.py
index 08044bb..f738fed 100644
--- a/ogs6py/classes/processvars.py
+++ b/ogs6py/classes/processvars.py
@@ -1,24 +1,31 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class ProcessVars(build_tree.BuildTree):
"""
Managing the process variables section in the project file.
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.pvs = self.populate_tree(self.root, 'process_variables', overwrite=True)
+ self.pvs = self.populate_tree(
+ self.root, "process_variables", overwrite=True
+ )
- def set_ic(self, **args):
+ def set_ic(self, **args: Any) -> None:
"""
Set initial conditions.
@@ -27,26 +34,41 @@ def set_ic(self, **args):
process_variable_name : `str`
components : `int` or `str`
order : `int` or `str`
- initial_condition` : `str`
+ initial_condition : `str`
+ compensate_non_equilibrium_initial_residuum : `str`
"""
self._convertargs(args)
if "process_variable_name" not in args:
- raise KeyError("No process_variable_name given")
+ msg = "No process_variable_name given"
+ raise KeyError(msg)
if "components" not in args:
- raise KeyError("Please provide the number of components \
- of the given process variable.")
+ msg = """Please provide the number of components \
+ of the given process variable."""
+
+ raise KeyError(msg)
if "order" not in args:
- raise KeyError("Out of order. Please specify the polynomial order \
- of the process variable's shape functions.")
+ msg = """Out of order. Please specify the polynomial order \
+ of the process variable's shape functions."""
+ raise KeyError(msg)
if "initial_condition" not in args:
- raise KeyError("No initial_condition specified.")
- pv = self.populate_tree(self.pvs, 'process_variable')
- self.populate_tree(pv, 'name', text=args['process_variable_name'])
- self.populate_tree(pv, 'components', text=args['components'])
- self.populate_tree(pv, 'order', text=args['order'])
- self.populate_tree(pv, 'initial_condition', text=args['initial_condition'])
+ msg = "No initial_condition specified."
+ raise KeyError(msg)
+ pv = self.populate_tree(self.pvs, "process_variable")
+ self.populate_tree(pv, "name", text=args["process_variable_name"])
+ self.populate_tree(pv, "components", text=args["components"])
+ self.populate_tree(pv, "order", text=args["order"])
+ compens = "compensate_non_equilibrium_initial_residuum"
+ boolmapping = {True: "true", False: "false"}
+ if compens in args:
+ if isinstance(args[compens], bool):
+ self.populate_tree(pv, compens, text=boolmapping[args[compens]])
+ else:
+ self.populate_tree(pv, compens, text=args[compens])
+ self.populate_tree(
+ pv, "initial_condition", text=args["initial_condition"]
+ )
- def add_bc(self, **args):
+ def add_bc(self, **args: Any) -> None:
"""
Adds a boundary condition.
@@ -63,45 +85,71 @@ def add_bc(self, **args):
"""
self._convertargs(args)
if "process_variable_name" not in args:
- raise KeyError("No process variable name specified.")
+ msg = "No process variable name specified."
+ raise KeyError(msg)
if "type" not in args:
- raise KeyError("No type given.")
- process_variable_name = args['process_variable_name']
- pv = self.root.find(f"./process_variables/process_variable[name=\'{process_variable_name}\']")
+ msg = "No type given."
+ raise KeyError(msg)
+ process_variable_name = args["process_variable_name"]
+ pv = self.root.find(
+ f"./process_variables/process_variable[name='{process_variable_name}']"
+ )
if pv is None:
- raise KeyError("You need to set initial condition for that process variable first.")
+ msg = "You need to set initial condition for that process variable first."
+ raise KeyError(msg)
boundary_conditions = pv.find("./boundary_conditions")
if boundary_conditions is None:
- boundary_conditions = self.populate_tree(pv, 'boundary_conditions')
- boundary_condition = self.populate_tree(boundary_conditions, 'boundary_condition')
- self.populate_tree(boundary_condition, 'type', text=args['type'])
+ boundary_conditions = self.populate_tree(pv, "boundary_conditions")
+ boundary_condition = self.populate_tree(
+ boundary_conditions, "boundary_condition"
+ )
+ self.populate_tree(boundary_condition, "type", text=args["type"])
if "geometrical_set" in args:
if "geometry" not in args:
- raise KeyError("You need to provide a geometry.")
- self.populate_tree(boundary_condition, 'geometrical_set', text=args['geometrical_set'])
- self.populate_tree(boundary_condition, 'geometry', text=args['geometry'])
+ msg = "You need to provide a geometry."
+ raise KeyError(msg)
+ self.populate_tree(
+ boundary_condition,
+ "geometrical_set",
+ text=args["geometrical_set"],
+ )
+ self.populate_tree(
+ boundary_condition, "geometry", text=args["geometry"]
+ )
elif "mesh" in args:
- self.populate_tree(boundary_condition, 'mesh', text=args['mesh'])
+ self.populate_tree(boundary_condition, "mesh", text=args["mesh"])
else:
- raise KeyError("You should provide either a geometrical set \
- or a mesh to define BC for.")
+ msg = """ou should provide either a geometrical set \
+ or a mesh to define BC for."""
+ raise KeyError(msg)
if "parameter" in args:
if "component" in args:
- self.populate_tree(boundary_condition, 'component', text=args['component'])
- self.populate_tree(boundary_condition, 'parameter', text=args['parameter'])
+ self.populate_tree(
+ boundary_condition, "component", text=args["component"]
+ )
+ self.populate_tree(
+ boundary_condition, "parameter", text=args["parameter"]
+ )
elif "bc_object" in args:
if "component" in args:
- self.populate_tree(boundary_condition, 'component', text=args['component'])
- self.populate_tree(boundary_condition, 'bc_object', text=args['bc_object'])
+ self.populate_tree(
+ boundary_condition, "component", text=args["component"]
+ )
+ self.populate_tree(
+ boundary_condition, "bc_object", text=args["bc_object"]
+ )
elif "u_0" in args:
if "alpha" in args:
- self.populate_tree(boundary_condition, 'alpha', text=args['alpha'])
- self.populate_tree(boundary_condition, 'u_0', text=args['u_0'])
+ self.populate_tree(
+ boundary_condition, "alpha", text=args["alpha"]
+ )
+ self.populate_tree(boundary_condition, "u_0", text=args["u_0"])
else:
- raise KeyError("Please provide the parameter for Dirichlet \
- or Neumann BCs/bc_object for Python BCs")
+ msg = """Please provide the parameter for Dirichlet \
+ or Neumann BCs/bc_object for Python BCs"""
+ raise KeyError(msg)
- def add_st(self, **args):
+ def add_st(self, **args: Any) -> None:
"""
add a source term
@@ -118,40 +166,58 @@ def add_st(self, **args):
"""
self._convertargs(args)
if "process_variable_name" not in args:
- raise KeyError("No process variable name specified.")
+ msg = "No process variable name specified."
+ raise KeyError(msg)
if "type" not in args:
- raise KeyError("No type given.")
- process_variable_name = args['process_variable_name']
- pv = self.root.find(f"./process_variables/process_variable[name=\'{process_variable_name}\']")
+ msg = "No type given."
+ raise KeyError(msg)
+ process_variable_name = args["process_variable_name"]
+ pv = self.root.find(
+ f"./process_variables/process_variable[name='{process_variable_name}']"
+ )
if pv is None:
- raise KeyError("You need to set initial condition for that process variable first.")
+ msg = "You need to set initial condition for that process variable first."
+ raise KeyError(msg)
source_terms = pv.find("./source_terms")
if source_terms is None:
- source_terms = self.populate_tree(pv, 'source_terms')
- source_term = self.populate_tree(source_terms, 'source_term')
- self.populate_tree(source_term, 'type', text=args['type'])
+ source_terms = self.populate_tree(pv, "source_terms")
+ source_term = self.populate_tree(source_terms, "source_term")
+ self.populate_tree(source_term, "type", text=args["type"])
if "geometrical_set" in args:
if "geometry" not in args:
- raise KeyError("You need to provide a geometry.")
- self.populate_tree(source_term, 'geometrical_set', text=args['geometrical_set'])
- self.populate_tree(source_term, 'geometry', text=args['geometry'])
+ msg = "You need to provide a geometry."
+ raise KeyError(msg)
+ self.populate_tree(
+ source_term, "geometrical_set", text=args["geometrical_set"]
+ )
+ self.populate_tree(source_term, "geometry", text=args["geometry"])
elif "mesh" in args:
- self.populate_tree(source_term, 'mesh', text=args['mesh'])
+ self.populate_tree(source_term, "mesh", text=args["mesh"])
else:
- raise KeyError("You should provide either a geometrical set \
- or a mesh to define STs for.")
+ msg = "You should provide either a geometrical set \
+ or a mesh to define STs for."
+ raise KeyError(msg)
if "parameter" in args:
if "component" in args:
- self.populate_tree(source_term, 'component', text=args['component'])
- self.populate_tree(source_term, 'parameter', text=args['parameter'])
+ self.populate_tree(
+ source_term, "component", text=args["component"]
+ )
+ self.populate_tree(source_term, "parameter", text=args["parameter"])
elif "source_term_object" in args:
if "component" in args:
- self.populate_tree(source_term, 'component', text=args['component'])
- self.populate_tree(source_term, 'source_term_object', text=args['source_term_object'])
+ self.populate_tree(
+ source_term, "component", text=args["component"]
+ )
+ self.populate_tree(
+ source_term,
+ "source_term_object",
+ text=args["source_term_object"],
+ )
elif "u_0" in args:
if "alpha" in args:
- self.populate_tree(source_term, 'alpha', text=args['alpha'])
- self.populate_tree(source_term, 'u_0', text=args['u_0'])
+ self.populate_tree(source_term, "alpha", text=args["alpha"])
+ self.populate_tree(source_term, "u_0", text=args["u_0"])
else:
- raise KeyError("Please provide the parameter for Dirichlet \
- or Neumann ST/source_term_object for Python STs")
+ msg = """Please provide the parameter for Dirichlet \
+ or Neumann ST/source_term_object for Python STs"""
+ raise KeyError(msg)
diff --git a/ogs6py/classes/properties.py b/ogs6py/classes/properties.py
index 548bdf5..737cac9 100644
--- a/ogs6py/classes/properties.py
+++ b/ogs6py/classes/properties.py
@@ -1,32 +1,40 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
+from __future__ import annotations
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from ogstools.ogs6py.ogs import OGS
+
+from collections.abc import Generator
from dataclasses import dataclass, field
-from typing import List
+from typing import Any
+
from lxml import etree as ET
+
@dataclass
class Value:
- medium : str
- value : float
+ medium: str
+ value: float | None
@dataclass
class Property:
- title : str
- symbol : str
- unit : str
- value : List[Value] = field(default_factory=list)
+ title: str
+ symbol: str
+ unit: str
+ value: list[Value] = field(default_factory=list)
- def _dict(self):
- a = {
+ def _dict(self) -> dict[str, Any]:
+ a: dict[str, Any] = {
"title": self.title,
"symbol": self.symbol,
"unit": self.unit,
@@ -36,50 +44,142 @@ def _dict(self):
return a
-
@dataclass
class PropertySet:
- property : List[Property] = field(default_factory=list)
+ property: list[Property] = field(default_factory=list)
- def __len__(self):
+ def __len__(self) -> int:
"""Number of time steps"""
return len(self.property)
- def __iter__(self):
+ def __iter__(self) -> Generator:
for v in self.property:
yield v._dict()
-property_dict = {"Solid": {"density": {"title": "Solid density", "symbol": "$\\rho_\\text{s}$", "unit": "kg m$^{-3}$"},
- "specific_heat_capacity": {"title": "Specific heat capacity", "symbol": "$c_\\text{s}$", "unit": "J kg$^{-1}$ K$^{-1}$"},
- "thermal_expansivity": {"title": "Thermal expansivity", "symbol": "$a_s$", "unit": "K$^{-1}$"},
- "youngs_modulus": {"title": "Young's modulus", "symbol": "$E$", "unit": "Pa"},
- "poissons_ratio": {"title": "Poisson's ratio", "symbol": "$\\nu$", "unit": "1"},
-
- },
- "Medium": {"porosity": {"title": "Porosity", "symbol": "$\phi$", "unit": "1"},
- "biot_coefficient": {"title": "Biot-Willis coefficient", "symbol": "$\\alpha_\mathrm{B}$", "unit": "1"},
- "permeability": {"title": "Intrinsic permeability", "symbol": "$k$", "unit": "m$^2$"},
- "thermal_conductivity": {"title": "Thermal conductivity", "symbol": "$\lambda$", "unit": "W m$^{-1}$ K$^{-1}$"},
- "vgsat_residual_liquid_saturation": {"title": "Saturation: Van Genuchten, \\\ residual liquid saturation", "symbol": "$S^r_\\text{L}$", "unit": "1"},
- "vgsat_residual_gas_saturation": {"title": "Saturation: Van Genuchten, \\\ residual gas saturation ", "symbol": "$S^r_\\text{g}$", "unit": "1"},
- "vgsat_exponent": {"title": "Saturation: Van Genuchten, \\\ exponent", "symbol": "$m$", "unit": "1"},
- "vgsat_p_b": {"title": "Saturation: Van Genuchten, \\\ entry pressure", "symbol": "$p_b$", "unit": "Pa"},
- "vgrelperm_residual_liquid_saturation": {"title": "Relative permeability: Van Genuchten, \\\ residual liquid saturation ", "symbol": "$S^r_\\text{L}$", "unit": "1"},
- "vgrelperm_residual_gas_saturation": {"title": "Relative permeability: Van Genuchten, \\\ residual gas saturation ", "symbol": "$S^r_\\text{g}$", "unit": "1"},
- "vgrelperm_exponent": {"title": "Relative permeability: Van Genuchten, \\\ exponent", "symbol": "$m$", "unit": "1"},
- "vgrelperm_minimum_relative_permeability_liquid": {"title": "Relative permeability: Van Genuchten, \\\ minimmum relative permeability", "symbol": "$k^\\text{min}_r$", "unit": "1"},
- },
- "AqueousLiquid": {"viscosity": {"title": "Liquid phase viscosity", "symbol": "$\mu_\mathrm{LR}$", "unit": "Pa s"},
- "density": {"title": "Liquid phase density", "symbol": "$\\rho_\mathrm{LR}$", "unit": "kg m$^{-3}$"},
- "specific_heat_capacity": {"title": "Liquid specific heat capacity", "symbol": "$c_\\text{LR}$", "unit": "J kg$^{-1}$ K$^{-1}$"},}}
-location_pointer = {"Solid": "phases/phase[type='Solid']/",
- "Medium": "",
- "AqueousLiquid": "phases/phase[type='AqueousLiquid']/"}
-
-def expand_tensors(obj, numofmedia, multidim_prop, root, location):
+
+property_dict = {
+ "Solid": {
+ "density": {
+ "title": "Solid density",
+ "symbol": "$\\rho_\\text{s}$",
+ "unit": "kg m$^{-3}$",
+ },
+ "specific_heat_capacity": {
+ "title": "Specific heat capacity",
+ "symbol": "$c_\\text{s}$",
+ "unit": "J kg$^{-1}$ K$^{-1}$",
+ },
+ "thermal_expansivity": {
+ "title": "Thermal expansivity",
+ "symbol": "$a_s$",
+ "unit": "K$^{-1}$",
+ },
+ "youngs_modulus": {
+ "title": "Young's modulus",
+ "symbol": "$E$",
+ "unit": "Pa",
+ },
+ "poissons_ratio": {
+ "title": "Poisson's ratio",
+ "symbol": "$\\nu$",
+ "unit": "1",
+ },
+ },
+ "Medium": {
+ "porosity": {"title": "Porosity", "symbol": r"$\phi$", "unit": "1"},
+ "biot_coefficient": {
+ "title": "Biot-Willis coefficient",
+ "symbol": "$\\alpha_\\mathrm{B}$",
+ "unit": "1",
+ },
+ "permeability": {
+ "title": "Intrinsic permeability",
+ "symbol": "$k$",
+ "unit": "m$^2$",
+ },
+ "thermal_conductivity": {
+ "title": "Thermal conductivity",
+ "symbol": r"$\lambda$",
+ "unit": "W m$^{-1}$ K$^{-1}$",
+ },
+ "vgsat_residual_liquid_saturation": {
+ "title": "Saturation: Van Genuchten, \\\\ residual liquid saturation",
+ "symbol": "$S^r_\\text{L}$",
+ "unit": "1",
+ },
+ "vgsat_residual_gas_saturation": {
+ "title": "Saturation: Van Genuchten, \\\\ residual gas saturation ",
+ "symbol": "$S^r_\\text{g}$",
+ "unit": "1",
+ },
+ "vgsat_exponent": {
+ "title": "Saturation: Van Genuchten, \\\\ exponent",
+ "symbol": "$m$",
+ "unit": "1",
+ },
+ "vgsat_p_b": {
+ "title": "Saturation: Van Genuchten, \\\\ entry pressure",
+ "symbol": "$p_b$",
+ "unit": "Pa",
+ },
+ "vgrelperm_residual_liquid_saturation": {
+ "title": "Relative permeability: Van Genuchten, \\\\ residual liquid saturation ",
+ "symbol": "$S^r_\\text{L}$",
+ "unit": "1",
+ },
+ "vgrelperm_residual_gas_saturation": {
+ "title": "Relative permeability: Van Genuchten, \\\\ residual gas saturation ",
+ "symbol": "$S^r_\\text{g}$",
+ "unit": "1",
+ },
+ "vgrelperm_exponent": {
+ "title": "Relative permeability: Van Genuchten, \\\\ exponent",
+ "symbol": "$m$",
+ "unit": "1",
+ },
+ "vgrelperm_minimum_relative_permeability_liquid": {
+ "title": "Relative permeability: Van Genuchten, \\\\ minimmum relative permeability",
+ "symbol": "$k^\\text{min}_r$",
+ "unit": "1",
+ },
+ },
+ "AqueousLiquid": {
+ "viscosity": {
+ "title": "Liquid phase viscosity",
+ "symbol": r"$\mu_\mathrm{LR}$",
+ "unit": "Pa s",
+ },
+ "density": {
+ "title": "Liquid phase density",
+ "symbol": "$\\rho_\\mathrm{LR}$",
+ "unit": "kg m$^{-3}$",
+ },
+ "specific_heat_capacity": {
+ "title": "Liquid specific heat capacity",
+ "symbol": "$c_\\text{LR}$",
+ "unit": "J kg$^{-1}$ K$^{-1}$",
+ },
+ },
+}
+location_pointer = {
+ "Solid": "phases/phase[type='Solid']/",
+ "Medium": "",
+ "AqueousLiquid": "phases/phase[type='AqueousLiquid']/",
+}
+
+
+def expand_tensors(
+ obj: OGS,
+ numofmedia: int,
+ multidim_prop: dict[Any, Any],
+ root: ET.Element,
+ location: str,
+) -> None:
for medium_id in range(numofmedia):
medium = obj._get_medium_pointer(root, medium_id)
- const_props = medium.findall(f"./{location_pointer[location]}properties/property[type='Constant']/value")
+ const_props = medium.findall(
+ f"./{location_pointer[location]}properties/property[type='Constant']/value"
+ )
tobedeleted = []
for prop in const_props:
proplist = prop.text.split(" ")
@@ -97,21 +197,28 @@ def expand_tensors(obj, numofmedia, multidim_prop, root, location):
q = ET.SubElement(properties_level, "property")
for j, tag in enumerate(taglist):
r = ET.SubElement(q, tag)
- if not textlist[j] is None:
+ if textlist[j] is not None:
r.text = str(textlist[j])
for element in tobedeleted:
element.getparent().remove(element)
-def expand_van_genuchten(obj, numofmedia, root, location):
+
+def expand_van_genuchten(
+ obj: OGS, numofmedia: int, root: ET.Element, location: str
+) -> None:
for medium_id in range(numofmedia):
medium = obj._get_medium_pointer(root, medium_id)
- sat_vg_props = medium.findall(f"./{location_pointer[location]}properties/property[type='SaturationVanGenuchten']")
- relperm_vg_props = medium.findall(f"./{location_pointer[location]}properties/property[type='RelativePermeabilityVanGenuchten']")
+ sat_vg_props = medium.findall(
+ f"./{location_pointer[location]}properties/property[type='SaturationVanGenuchten']"
+ )
+ relperm_vg_props = medium.findall(
+ f"./{location_pointer[location]}properties/property[type='RelativePermeabilityVanGenuchten']"
+ )
vg_properties = [sat_vg_props, relperm_vg_props]
tobedeleted = []
for vg_property in vg_properties:
for prop in vg_property:
- proplist = [property for property in prop.getchildren()]
+ proplist = prop.getchildren()
const_taglist = ["name", "type", "value"]
prefix = ""
for subprop in proplist:
@@ -120,12 +227,16 @@ def expand_van_genuchten(obj, numofmedia, root, location):
elif "RelativePermeabilityVanGenuchten" in subprop.text:
prefix = "vgrelperm_"
for subprop in proplist:
- if not subprop.tag in ["name", "type"]:
- const_textlist = [prefix+subprop.tag, "Constant", subprop.text]
+ if subprop.tag not in ["name", "type"]:
+ const_textlist = [
+ prefix + subprop.tag,
+ "Constant",
+ subprop.text,
+ ]
q = ET.SubElement(prop.getparent(), "property")
for i, tag in enumerate(const_taglist):
r = ET.SubElement(q, tag)
- if not const_textlist[i] is None:
+ if const_textlist[i] is not None:
r.text = str(const_textlist[i])
tobedeleted.append(prop)
for element in tobedeleted:
diff --git a/ogs6py/classes/python_script.py b/ogs6py/classes/python_script.py
index 5a38080..a8dd493 100644
--- a/ogs6py/classes/python_script.py
+++ b/ogs6py/classes/python_script.py
@@ -1,25 +1,27 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class PythonScript(build_tree.BuildTree):
"""
Class managing python script in the project file
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
self.populate_tree(self.root, "python_script", overwrite=True)
-
- def set_pyscript(self, filename):
+ def set_pyscript(self, filename: str) -> None:
"""
Set a filename for a python script.
@@ -27,4 +29,6 @@ def set_pyscript(self, filename):
----------
filename : `str`
"""
- self.populate_tree(self.root, "python_script", text=filename, overwrite=True)
+ self.populate_tree(
+ self.root, "python_script", text=filename, overwrite=True
+ )
diff --git a/ogs6py/classes/timeloop.py b/ogs6py/classes/timeloop.py
index 716dbdf..e4a7d8d 100644
--- a/ogs6py/classes/timeloop.py
+++ b/ogs6py/classes/timeloop.py
@@ -1,27 +1,40 @@
-# -*- coding: utf-8 -*-
"""
-Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
Distributed under a Modified BSD License.
See accompanying file LICENSE or
http://www.opengeosys.org/project/license
"""
# pylint: disable=C0103, R0902, R0914, R0913
-from ogs6py.classes import build_tree
+from typing import Any
+
+from lxml import etree as ET
+
+from ogstools.ogs6py import build_tree
+
class TimeLoop(build_tree.BuildTree):
"""
Class managing the time loop in the project file
"""
- def __init__(self, tree):
+
+ def __init__(self, tree: ET.ElementTree) -> None:
self.tree = tree
self.root = self._get_root()
- self.time_loop = self.populate_tree(self.root, 'time_loop', overwrite=True)
- self.gpc = self.populate_tree(self.time_loop, "global_process_coupling", overwrite=True)
- self.processes = self.populate_tree(self.time_loop, 'processes', overwrite=True)
- self.output = self.populate_tree(self.time_loop, 'output', overwrite=True)
+ self.time_loop = self.populate_tree(
+ self.root, "time_loop", overwrite=True
+ )
+ self.gpc = self.populate_tree(
+ self.time_loop, "global_process_coupling", overwrite=True
+ )
+ self.processes = self.populate_tree(
+ self.time_loop, "processes", overwrite=True
+ )
+ self.output = self.populate_tree(
+ self.time_loop, "output", overwrite=True
+ )
- def add_process(self, **args):
+ def add_process(self, **args: Any) -> None:
"""
Add a process section to timeloop
@@ -39,44 +52,61 @@ def add_process(self, **args):
"""
self._convertargs(args)
if "process" not in args:
- raise KeyError("No process referenced")
- process_name = args['process']
- process = self.populate_tree(self.processes, 'process', attr={'ref': process_name})
+ msg = "No process referenced"
+ raise KeyError(msg)
+ process_name = args["process"]
+ process = self.populate_tree(
+ self.processes, "process", attr={"ref": process_name}
+ )
if "nonlinear_solver_name" not in args:
- raise KeyError("Please specify a name (nonlinear_solver_name) \
- for the nonlinear solver.")
- self.populate_tree(process, 'nonlinear_solver', text=args['nonlinear_solver_name'])
+ msg = """Please specify a name (nonlinear_solver_name) \
+ for the nonlinear solver."""
+ raise KeyError(msg)
+ self.populate_tree(
+ process, "nonlinear_solver", text=args["nonlinear_solver_name"]
+ )
if "convergence_type" not in args:
- raise KeyError("No convergence criterion given. \
- Specify convergence_type.")
- conv_crit = self.populate_tree(process, 'convergence_criterion')
- self.populate_tree(conv_crit, 'type', text=args['convergence_type'])
+ msg = """No convergence criterion given. \
+ Specify convergence_type."""
+ raise KeyError(msg)
+ conv_crit = self.populate_tree(process, "convergence_criterion")
+ self.populate_tree(conv_crit, "type", text=args["convergence_type"])
if "norm_type" not in args:
- raise KeyError("No norm_type given.")
- self.populate_tree(conv_crit, 'norm_type', text=args['norm_type'])
- if (args["convergence_type"] == "DeltaX") or (args["convergence_type"] == "Residual"):
- if (("abstols" in args) or ("reltols" in args)):
- raise KeyError("Plural tolerances only available for PerComponent conv. types")
+ msg = "No norm_type given."
+ raise KeyError(msg)
+ self.populate_tree(conv_crit, "norm_type", text=args["norm_type"])
+ if (args["convergence_type"] == "DeltaX") or (
+ args["convergence_type"] == "Residual"
+ ):
+ if ("abstols" in args) or ("reltols" in args):
+ msg = "Plural tolerances only available for PerComponent conv. types"
+ raise KeyError(msg)
if "abstol" in args:
- self.populate_tree(conv_crit, 'abstol', text=args['abstol'])
+ self.populate_tree(conv_crit, "abstol", text=args["abstol"])
if "reltol" in args:
- self.populate_tree(conv_crit, 'reltol', text=args['reltol'])
- elif (args["convergence_type"] == "PerComponentDeltaX") or (args["convergence_type"] == "PerComponentResidual"):
- if (("abstol" in args) or ("reltol" in args)):
- raise KeyError("Singular tolerances only available for scalar conv. types")
+ self.populate_tree(conv_crit, "reltol", text=args["reltol"])
+ elif (args["convergence_type"] == "PerComponentDeltaX") or (
+ args["convergence_type"] == "PerComponentResidual"
+ ):
+ if ("abstol" in args) or ("reltol" in args):
+ msg = (
+ "Singular tolerances only available for scalar conv. types"
+ )
+ raise KeyError(msg)
if "abstols" in args:
- self.populate_tree(conv_crit, 'abstols', text=args['abstols'])
+ self.populate_tree(conv_crit, "abstols", text=args["abstols"])
if "reltols" in args:
- self.populate_tree(conv_crit, 'reltols', text=args['reltols'])
+ self.populate_tree(conv_crit, "reltols", text=args["reltols"])
else:
- raise KeyError("No convergence_type given.")
+ msg = "No convergence_type given."
+ raise KeyError(msg)
if "time_discretization" not in args:
- raise KeyError("No time_discretization specified.")
- td = self.populate_tree(process, 'time_discretization')
- self.populate_tree(td, 'type', text=args['time_discretization'])
+ msg = "No time_discretization specified."
+ raise KeyError(msg)
+ td = self.populate_tree(process, "time_discretization")
+ self.populate_tree(td, "type", text=args["time_discretization"])
-
- def set_stepping(self, **args):
+ def set_stepping(self, **args: Any) -> None:
"""
Sets the time stepping
@@ -84,8 +114,7 @@ def set_stepping(self, **args):
----------
type : `str`
process : `str`
- process_count : `int` optional
- for staggered coupling
+ process_count : `int` for staggered coupling
t_initial : `int` or `str`
initial_dt : `float` or `str`
t_end : `int` or `str`
@@ -104,7 +133,8 @@ def set_stepping(self, **args):
"""
self._convertargs(args)
if "process" not in args:
- raise KeyError("Process reference missing")
+ msg = "Process reference missing"
+ raise KeyError(msg)
procs = self.processes.findall("./process")
process = None
procs_sub = []
@@ -113,64 +143,105 @@ def set_stepping(self, **args):
procs_sub.append(proc)
if "process_count" in args:
try:
- process = procs_sub[int(args['process_count'])]
+ process = procs_sub[int(args["process_count"])]
except KeyError:
- KeyError("Process count out of bounds.")
+ msg = "Process count out of bounds."
+ KeyError(msg)
else:
try:
process = procs_sub[-1]
except KeyError:
- KeyError("Process reference not found.")
+ msg = "Process reference not found."
+ KeyError(msg)
if "type" not in args:
- raise KeyError("No type given.")
- time_stepping = self.populate_tree(process, 'time_stepping')
- self.populate_tree(time_stepping, 'type', text=args['type'])
+ msg = "No type given."
+ raise KeyError(msg)
+ time_stepping = self.populate_tree(process, "time_stepping")
+ self.populate_tree(time_stepping, "type", text=args["type"])
if args["type"] == "FixedTimeStepping":
- self.populate_tree(time_stepping, 't_initial', text=args['t_initial'])
- self.populate_tree(time_stepping, 't_end', text=args['t_end'])
+ self.populate_tree(
+ time_stepping, "t_initial", text=args["t_initial"]
+ )
+ self.populate_tree(time_stepping, "t_end", text=args["t_end"])
if "repeat" in args and "delta_t" in args:
- ts = self.populate_tree(time_stepping, 'timesteps')
- if isinstance(args["repeat"], str) and isinstance(args["delta_t"], str):
- pair = self.populate_tree(ts, 'pair')
- self.populate_tree(pair, 'repeat', text=args['repeat'])
- self.populate_tree(pair, 'delta_t', text=args['delta_t'])
+ ts = self.populate_tree(time_stepping, "timesteps")
+ if isinstance(args["repeat"], str) and isinstance(
+ args["delta_t"], str
+ ):
+ pair = self.populate_tree(ts, "pair")
+ self.populate_tree(pair, "repeat", text=args["repeat"])
+ self.populate_tree(pair, "delta_t", text=args["delta_t"])
else:
for i, entry in enumerate(args["repeat"]):
- pair = self.populate_tree(ts, 'pair')
- self.populate_tree(pair, 'repeat', text=entry)
- self.populate_tree(pair, 'delta_t', text=args['delta_t'][i])
+ pair = self.populate_tree(ts, "pair")
+ self.populate_tree(pair, "repeat", text=entry)
+ self.populate_tree(
+ pair, "delta_t", text=args["delta_t"][i]
+ )
else:
- raise KeyError("No proper time stepping defined. \
- Please specify repeat and delta_t.")
+ msg = """No proper time stepping defined. \
+ Please specify repeat and delta_t."""
+ raise KeyError(msg)
elif args["type"] == "SingleStep":
pass
elif args["type"] == "IterationNumberBasedTimeStepping":
- self.populate_tree(time_stepping, 't_initial', text=args['t_initial'])
- self.populate_tree(time_stepping, 't_end', text=args['t_end'])
- self.populate_tree(time_stepping, 'initial_dt', text=args['initial_dt'])
- self.populate_tree(time_stepping, 'minimum_dt', text=args['minimum_dt'])
- self.populate_tree(time_stepping, 'maximum_dt', text=args['maximum_dt'])
- if isinstance(args["number_iterations"], str) and isinstance(args["multiplier"], str):
- self.populate_tree(time_stepping, 'number_iterations', text=args['number_iterations'])
- self.populate_tree(time_stepping, 'multiplier', text=args['multiplier'])
+ self.populate_tree(
+ time_stepping, "t_initial", text=args["t_initial"]
+ )
+ self.populate_tree(time_stepping, "t_end", text=args["t_end"])
+ self.populate_tree(
+ time_stepping, "initial_dt", text=args["initial_dt"]
+ )
+ self.populate_tree(
+ time_stepping, "minimum_dt", text=args["minimum_dt"]
+ )
+ self.populate_tree(
+ time_stepping, "maximum_dt", text=args["maximum_dt"]
+ )
+ if isinstance(args["number_iterations"], str) and isinstance(
+ args["multiplier"], str
+ ):
+ self.populate_tree(
+ time_stepping,
+ "number_iterations",
+ text=args["number_iterations"],
+ )
+ self.populate_tree(
+ time_stepping, "multiplier", text=args["multiplier"]
+ )
else:
- self.populate_tree(time_stepping, 'number_iterations', text=" ".join(str(x) for x in args['number_iterations']))
- self.populate_tree(time_stepping, 'multiplier', text=" ".join(str(x) for x in args['multiplier']))
+ self.populate_tree(
+ time_stepping,
+ "number_iterations",
+ text=" ".join(str(x) for x in args["number_iterations"]),
+ )
+ self.populate_tree(
+ time_stepping,
+ "multiplier",
+ text=" ".join(str(x) for x in args["multiplier"]),
+ )
elif args["type"] == "EvolutionaryPIDcontroller":
- self.populate_tree(time_stepping, 't_initial', text=args['t_initial'])
- self.populate_tree(time_stepping, 't_end', text=args['t_end'])
- self.populate_tree(time_stepping, 'dt_guess', text=args['dt_guess'])
- self.populate_tree(time_stepping, 'dt_min', text=args['dt_min'])
- self.populate_tree(time_stepping, 'dt_max', text=args['dt_max'])
- self.populate_tree(time_stepping, 'rel_dt_max', text=args['rel_dt_max'])
- self.populate_tree(time_stepping, 'rel_dt_min', text=args['rel_dt_min'])
- self.populate_tree(time_stepping, 'tol', text=args['tol'])
+ self.populate_tree(
+ time_stepping, "t_initial", text=args["t_initial"]
+ )
+ self.populate_tree(time_stepping, "t_end", text=args["t_end"])
+ self.populate_tree(time_stepping, "dt_guess", text=args["dt_guess"])
+ self.populate_tree(time_stepping, "dt_min", text=args["dt_min"])
+ self.populate_tree(time_stepping, "dt_max", text=args["dt_max"])
+ self.populate_tree(
+ time_stepping, "rel_dt_max", text=args["rel_dt_max"]
+ )
+ self.populate_tree(
+ time_stepping, "rel_dt_min", text=args["rel_dt_min"]
+ )
+ self.populate_tree(time_stepping, "tol", text=args["tol"])
else:
- raise KeyError("Specified time stepping scheme not valid.")
+ msg = "Specified time stepping scheme not valid."
+ raise KeyError(msg)
- def add_output(self, **args):
+ def add_output(self, **args: Any) -> None:
"""
Add output section.
@@ -189,83 +260,111 @@ def add_output(self, **args):
fixed_output_times : `list` or `str`
"""
if "type" not in args:
- raise KeyError("If you want to specify an output method, \
+ msg = """If you want to specify an output method, \
you need to provide type, \
- prefix and a list of variables.")
- self.populate_tree(self.output, 'type', text=args['type'])
+ prefix and a list of variables."""
+ raise KeyError(msg)
+ self.populate_tree(self.output, "type", text=args["type"])
if "prefix" in args:
- self.populate_tree(self.output, 'prefix', text=args['prefix'])
+ self.populate_tree(self.output, "prefix", text=args["prefix"])
if "suffix" in args:
- self.populate_tree(self.output, 'suffix', text=args['suffix'])
+ self.populate_tree(self.output, "suffix", text=args["suffix"])
if "data_mode" in args:
- self.populate_tree(self.output, 'data_mode', text=args['data_mode'])
+ self.populate_tree(self.output, "data_mode", text=args["data_mode"])
if "compress_output" in args:
if isinstance(args["compress_output"], bool):
if args["compress_output"] is True:
- self.populate_tree(self.output, 'compress_output', text="true")
+ self.populate_tree(
+ self.output, "compress_output", text="true"
+ )
else:
- self.populate_tree(self.output, 'compress_output', text="false")
+ self.populate_tree(
+ self.output, "compress_output", text="false"
+ )
else:
- self.populate_tree(self.output, 'compress_output', text=args["compress_output"])
+ self.populate_tree(
+ self.output, "compress_output", text=args["compress_output"]
+ )
if "output_iteration_results" in args:
if isinstance(args["output_iteration_results"], bool):
if args["output_iteration_results"] is True:
- self.populate_tree(self.output, 'output_iteration_results', text="true")
+ self.populate_tree(
+ self.output, "output_iteration_results", text="true"
+ )
else:
- self.populate_tree(self.output, 'output_iteration_results', text="false")
+ self.populate_tree(
+ self.output, "output_iteration_results", text="false"
+ )
else:
- self.populate_tree(self.output, 'output_iteration_results', text=args["output_iteration_results"])
+ self.populate_tree(
+ self.output,
+ "output_iteration_results",
+ text=args["output_iteration_results"],
+ )
if "meshes" in args:
- meshes = self.populate_tree(self.output, 'meshes')
+ meshes = self.populate_tree(self.output, "meshes")
if isinstance(args["meshes"], str):
- self.populate_tree(meshes, 'mesh', text=args["meshes"])
+ self.populate_tree(meshes, "mesh", text=args["meshes"])
else:
for mesh in args["meshes"]:
- self.populate_tree(meshes, 'mesh', text=mesh)
+ self.populate_tree(meshes, "mesh", text=mesh)
# material_id attribute missing
if "repeat" in args:
- timesteps = self.populate_tree(self.output, 'timesteps')
+ timesteps = self.populate_tree(self.output, "timesteps")
if "each_steps" not in args:
- raise KeyError("each_steps is a required tag if repeat is given.")
- if isinstance(args["repeat"], list) and isinstance(args["each_steps"], list):
+ msg = "each_steps is a required tag if repeat is given."
+ raise KeyError(msg)
+ if isinstance(args["repeat"], list) and isinstance(
+ args["each_steps"], list
+ ):
for i, entry in enumerate(args["repeat"]):
- pair = self.populate_tree(timesteps, 'pair')
- self.populate_tree(pair, 'repeat', text=entry)
- self.populate_tree(pair, 'each_steps', text=args['each_steps'][i])
+ pair = self.populate_tree(timesteps, "pair")
+ self.populate_tree(pair, "repeat", text=entry)
+ self.populate_tree(
+ pair, "each_steps", text=args["each_steps"][i]
+ )
else:
- pair = self.populate_tree(timesteps, 'pair')
- self.populate_tree(pair, 'repeat', text=args["repeat"])
- self.populate_tree(pair, 'each_steps', text=args['each_steps'])
- variables = self.populate_tree(self.output, 'variables')
+ pair = self.populate_tree(timesteps, "pair")
+ self.populate_tree(pair, "repeat", text=args["repeat"])
+ self.populate_tree(pair, "each_steps", text=args["each_steps"])
+ variables = self.populate_tree(self.output, "variables")
if "variables" in args:
if isinstance(args["variables"], list):
for var in args["variables"]:
- self.populate_tree(variables, 'variable', text=var)
+ self.populate_tree(variables, "variable", text=var)
else:
- raise KeyError("parameter variables needs to be a list")
+ msg = "parameter variables needs to be a list"
+ raise KeyError(msg)
if "fixed_output_times" in args:
if isinstance(args["fixed_output_times"], list):
- self.populate_tree(self.output, 'fixed_output_times', text=" ".join(str(x) for x in args["fixed_output_times"]))
+ self.populate_tree(
+ self.output,
+ "fixed_output_times",
+ text=" ".join(str(x) for x in args["fixed_output_times"]),
+ )
else:
- self.populate_tree(self.output, 'fixed_output_times', text=args["fixed_output_times"])
-
+ self.populate_tree(
+ self.output,
+ "fixed_output_times",
+ text=args["fixed_output_times"],
+ )
- def add_time_stepping_pair(self, **args):
+ def add_time_stepping_pair(self, **args: Any) -> None:
"""
add a time stepping pair
Parameters
----------
process : `str`
- process_count : `int` optional
- for staggered coupling
+ process_count : `int` optional, for staggered coupling
repeat : `int` or `str` or `list`
delta_t : `int` or `str` or `list`
"""
self._convertargs(args)
if "process" not in args:
- raise KeyError("No process referenced")
+ msg = "No process referenced"
+ raise KeyError(msg)
procs = self.processes.findall("./process")
process = None
procs_sub = []
@@ -274,32 +373,41 @@ def add_time_stepping_pair(self, **args):
procs_sub.append(proc)
if "process_count" in args:
try:
- process = procs_sub[int(args['process_count'])]
+ process = procs_sub[int(args["process_count"])]
except KeyError:
- KeyError("Process count out of bounds.")
+ msg = "Process count out of bounds."
+ KeyError(msg)
else:
try:
process = procs_sub[-1]
except KeyError:
- KeyError("Process reference not found.")
+ msg = "Process reference not found."
+ KeyError(msg)
+ if process is None:
+ msg = "Could not find any associated process"
+ raise AttributeError(msg)
ts = process.find("./time_stepping/timesteps")
if ts is None:
- raise RuntimeError("Cannot find time stepping section in the input file.")
+ msg = "Cannot find time stepping section in the input file."
+ raise RuntimeError(msg)
if "repeat" in args and "delta_t" in args:
- if isinstance(args["repeat"], str) and isinstance(args["delta_t"], str):
- pair = self.populate_tree(ts, 'pair')
- self.populate_tree(pair, 'repeat', text=args['repeat'])
- self.populate_tree(pair, 'delta_t', text=args['delta_t'])
+ if isinstance(args["repeat"], str) and isinstance(
+ args["delta_t"], str
+ ):
+ pair = self.populate_tree(ts, "pair")
+ self.populate_tree(pair, "repeat", text=args["repeat"])
+ self.populate_tree(pair, "delta_t", text=args["delta_t"])
else:
for i, entry in enumerate(args["repeat"]):
- pair = self.populate_tree(ts, 'pair')
- self.populate_tree(pair, 'repeat', text=entry)
- self.populate_tree(pair, 'delta_t', text=args['delta_t'][i])
+ pair = self.populate_tree(ts, "pair")
+ self.populate_tree(pair, "repeat", text=entry)
+ self.populate_tree(pair, "delta_t", text=args["delta_t"][i])
else:
- raise KeyError("You muss provide repeat and delta_t attributes to \
- define additional time stepping pairs.")
+ msg = """You muss provide repeat and delta_t attributes to \
+ define additional time stepping pairs."""
+ raise KeyError(msg)
- def add_output_pair(self, **args):
+ def add_output_pair(self, **args: Any) -> None:
"""
add an output pair
@@ -309,29 +417,33 @@ def add_output_pair(self, **args):
each_steps : `int` or `str` or `list`
"""
self._convertargs(args)
- timesteps = self.populate_tree(self.output, 'timesteps', overwrite=True)
+ timesteps = self.populate_tree(self.output, "timesteps", overwrite=True)
if "repeat" in args and "each_steps" in args:
- if isinstance(args["repeat"], list) and isinstance(args["each_steps"], list):
+ if isinstance(args["repeat"], list) and isinstance(
+ args["each_steps"], list
+ ):
for i, entry in enumerate(args["repeat"]):
- pair = self.populate_tree(timesteps, 'pair')
- self.populate_tree(pair, 'repeat', text=entry)
- self.populate_tree(pair, 'each_steps', text=args['each_steps'][i])
+ pair = self.populate_tree(timesteps, "pair")
+ self.populate_tree(pair, "repeat", text=entry)
+ self.populate_tree(
+ pair, "each_steps", text=args["each_steps"][i]
+ )
else:
- pair = self.populate_tree(timesteps, 'pair')
- self.populate_tree(pair, 'repeat', text=args["repeat"])
- self.populate_tree(pair, 'each_steps', text=args['each_steps'])
+ pair = self.populate_tree(timesteps, "pair")
+ self.populate_tree(pair, "repeat", text=args["repeat"])
+ self.populate_tree(pair, "each_steps", text=args["each_steps"])
else:
- raise KeyError("You muss provide repeat and each_steps attributes \
- to define additional output pairs.")
+ msg = """You muss provide repeat and each_steps attributes \
+ to define additional output pairs."""
+ raise KeyError(msg)
- def add_global_process_coupling(self, **args):
+ def add_global_process_coupling(self, **args: Any) -> None:
"""
Add a process section to timeloop
Parameters
----------
- max_iter : `str`
- optional, needs to be specified once
+ max_iter : `str` optional, needs to be specified once
convergence_type : `str`
abstol : `str`
abstols : `str`
@@ -343,38 +455,56 @@ def add_global_process_coupling(self, **args):
"""
self._convertargs(args)
if "max_iter" in args:
- self.populate_tree(self.gpc, "max_iter", text=args['max_iter'], overwrite=True)
- convergence_criteria = self.populate_tree(self.gpc, "convergence_criteria", overwrite=True)
+ self.populate_tree(
+ self.gpc, "max_iter", text=args["max_iter"], overwrite=True
+ )
+ convergence_criteria = self.populate_tree(
+ self.gpc, "convergence_criteria", overwrite=True
+ )
if "convergence_type" not in args:
- raise KeyError("No convergence criterion given. \
- Specify convergence_type.")
- conv_crit = self.populate_tree(convergence_criteria, 'convergence_criterion')
- self.populate_tree(conv_crit, 'type', text=args['convergence_type'])
+ msg = """No convergence criterion given. \
+ Specify convergence_type."""
+ raise KeyError(msg)
+ conv_crit = self.populate_tree(
+ convergence_criteria, "convergence_criterion"
+ )
+ self.populate_tree(conv_crit, "type", text=args["convergence_type"])
if "norm_type" not in args:
- raise KeyError("No norm_type given.")
- self.populate_tree(conv_crit, 'norm_type', text=args['norm_type'])
- if (args["convergence_type"] == "DeltaX") or (args["convergence_type"] == "Residual"):
- if (("abstols" in args) or ("reltols" in args)):
- raise KeyError("Plural tolerances only available for PerComponent conv. types")
+ msg = "No norm_type given."
+ raise KeyError(msg)
+ self.populate_tree(conv_crit, "norm_type", text=args["norm_type"])
+ if (args["convergence_type"] == "DeltaX") or (
+ args["convergence_type"] == "Residual"
+ ):
+ if ("abstols" in args) or ("reltols" in args):
+ msg = "Plural tolerances only available for PerComponent conv. types"
+ raise KeyError(msg)
if "abstol" in args:
- self.populate_tree(conv_crit, 'abstol', text=args['abstol'])
+ self.populate_tree(conv_crit, "abstol", text=args["abstol"])
if "reltol" in args:
- self.populate_tree(conv_crit, 'reltol', text=args['reltol'])
- elif (args["convergence_type"] == "PerComponentDeltaX") or (args["convergence_type"] == "PerComponentResidual"):
- if (("abstol" in args) or ("reltol" in args)):
- raise KeyError("Singular tolerances only available for scalar conv. types")
+ self.populate_tree(conv_crit, "reltol", text=args["reltol"])
+ elif (args["convergence_type"] == "PerComponentDeltaX") or (
+ args["convergence_type"] == "PerComponentResidual"
+ ):
+ if ("abstol" in args) or ("reltol" in args):
+ msg = (
+ "Singular tolerances only available for scalar conv. types"
+ )
+ raise KeyError(msg)
if "abstols" in args:
- self.populate_tree(conv_crit, 'abstols', text=args['abstols'])
+ self.populate_tree(conv_crit, "abstols", text=args["abstols"])
if "reltols" in args:
- self.populate_tree(conv_crit, 'reltols', text=args['reltols'])
+ self.populate_tree(conv_crit, "reltols", text=args["reltols"])
else:
- raise KeyError("No convergence_type given.")
+ msg = "No convergence_type given."
+ raise KeyError(msg)
if "local_coupling_processes" in args:
if "local_coupling_processes_max_iter" not in args:
- raise KeyError("local_coupling_processes_max_iter parameter is missing")
+ msg = "local_coupling_processes_max_iter parameter is missing"
+ raise KeyError(msg)
lcp = self.populate_tree(self.gpc, "local_coupling_processes")
- self.populate_tree(lcp, "max_iter", text=args['local_coupling_processes_max_iter'])
+ self.populate_tree(
+ lcp, "max_iter", text=args["local_coupling_processes_max_iter"]
+ )
for name in args["local_coupling_processes"]:
self.populate_tree(lcp, "process_name", text=name)
-
-
diff --git a/ogs6py/ogs.py b/ogs6py/ogs.py
index 3f02788..38cd10e 100644
--- a/ogs6py/ogs.py
+++ b/ogs6py/ogs.py
@@ -1,6 +1,5 @@
-# -*- coding: utf-8 -*-
"""
-ogs6py is a python-API for the OpenGeoSys finite element sofware.
+ogs6py is a python-API for the OpenGeoSys finite element software.
Its main functionalities include creating and altering OGS6 input files as well as executing OGS.
Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
@@ -11,19 +10,46 @@
"""
# pylint: disable=C0103, R0902, R0914, R0913
-import sys
+
+import copy
import os
+import shutil
import subprocess
+import sys
import time
-import copy
-import shutil
+from pathlib import Path
+from typing import Any
+
import pandas as pd
from lxml import etree as ET
-from ogs6py.classes import (display, geo, mesh, python_script, processes, media, timeloop,
- local_coordinate_system, parameters, curves, processvars, linsolvers, nonlinsolvers)
+
+from ogs6py.classes import (
+ curves,
+ display,
+ geo,
+ linsolvers,
+ local_coordinate_system,
+ media,
+ mesh,
+ nonlinsolvers,
+ parameters,
+ processes,
+ processvars,
+ python_script,
+ timeloop,
+)
+from ogs6py.classes.properties import (
+ Property,
+ PropertySet,
+ Value,
+ expand_tensors,
+ expand_van_genuchten,
+ location_pointer,
+ property_dict,
+)
import ogs6py.log_parser.log_parser as parser
import ogs6py.log_parser.common_ogs_analyses as parse_fcts
-from ogs6py.classes.properties import *
+
class OGS:
"""Class for an OGS6 model.
@@ -38,42 +64,44 @@ class OGS:
INPUT_FILE : `str`, optional
Filename of the input project file
XMLSTRING : `str`,optional
+ String containing the XML tree
OMP_NUM_THREADS : `int`, optional
Sets the environmentvariable before OGS execution to restrict number of OMP Threads
VERBOSE : `bool`, optional
Default: False
+
"""
- def __init__(self, **args):
+
+ def __init__(self, **args: Any) -> None:
sys.setrecursionlimit(10000)
- self.tag = []
- self.logfile = "out.log"
+ self.logfile: Path = Path("out.log")
self.tree = None
- self.include_elements = []
- self.include_files = []
- self.add_includes = []
- self.output_dir = ""
- if "VERBOSE" in args:
- self.verbose = args["VERBOSE"]
- else:
- self.verbose = False
- if "OMP_NUM_THREADS" in args:
- self.threads = args["OMP_NUM_THREADS"]
- else:
- self.threads = None
+ self.include_elements: list[ET.Element] = []
+ self.include_files: list[Path] = []
+ self.add_includes: list[dict[str, str]] = []
+ self.output_dir: Path = Path() # default -> current dir
+ self.verbose: bool = args.get("VERBOSE", False)
+ self.threads: int = args.get("OMP_NUM_THREADS", None)
+ self.asm_threads: int = args.get("OGS_ASM_THREADS", self.threads)
+ self.inputfile: Path | None = None
+ self.folder: Path = Path()
+
if "PROJECT_FILE" in args:
- self.prjfile = args['PROJECT_FILE']
+ self.prjfile = Path(args["PROJECT_FILE"])
else:
print("PROJECT_FILE for output not given. Calling it default.prj.")
- self.prjfile = "default.prj"
+ self.prjfile = Path("default.prj")
if "INPUT_FILE" in args:
- if os.path.isfile(args['INPUT_FILE']) is True:
- self.inputfile = args['INPUT_FILE']
- self.folder, _ = os.path.split(self.inputfile)
+ input_file = Path(args["INPUT_FILE"])
+ if input_file.is_file():
+ self.inputfile = input_file
+ self.folder = input_file.parent
_ = self._get_root()
if self.verbose is True:
display.Display(self.tree)
else:
- raise RuntimeError(f"Input project file {args['INPUT_FILE']} not found.")
+ msg = f"Input project file {args['INPUT_FILE']} not found."
+ raise FileNotFoundError(msg)
else:
self.inputfile = None
self.root = ET.Element("OpenGeoSysProject")
@@ -83,7 +111,7 @@ def __init__(self, **args):
tree_ = ET.fromstring(tree_string, parser=parse)
self.tree = ET.ElementTree(tree_)
if "XMLSTRING" in args:
- root = ET.fromstring(args['XMLSTRING'])
+ root = ET.fromstring(args["XMLSTRING"])
self.tree = ET.ElementTree(root)
self.geometry = geo.Geo(self.tree)
self.mesh = mesh.Mesh(self.tree)
@@ -91,47 +119,57 @@ def __init__(self, **args):
self.python_script = python_script.PythonScript(self.tree)
self.media = media.Media(self.tree)
self.time_loop = timeloop.TimeLoop(self.tree)
- self.local_coordinate_system = local_coordinate_system.LocalCoordinateSystem(self.tree)
+ self.local_coordinate_system = (
+ local_coordinate_system.LocalCoordinateSystem(self.tree)
+ )
self.parameters = parameters.Parameters(self.tree)
self.curves = curves.Curves(self.tree)
self.process_variables = processvars.ProcessVars(self.tree)
self.nonlinear_solvers = nonlinsolvers.NonLinSolvers(self.tree)
self.linear_solvers = linsolvers.LinSolvers(self.tree)
- def __replace_blocks_by_includes(self):
+ def __replace_blocks_by_includes(self) -> None:
for i, file in enumerate(self.include_files):
parent_element = self.include_elements[i].getparent()
include_element = ET.SubElement(parent_element, "include")
- if self.folder == "":
- file_ = file
- else:
- file_ = file.replace(f"{self.folder}/","")
- include_element.set("file", file_)
+ file_ = file if self.folder.cwd() else file.relative_to(self.folder)
+ include_element.set("file", str(file_))
parse = ET.XMLParser(remove_blank_text=True)
- include_string = ET.tostring(self.include_elements[i], pretty_print=True)
+ include_string = ET.tostring(
+ self.include_elements[i], pretty_print=True
+ )
include_parse = ET.fromstring(include_string, parser=parse)
include_tree = ET.ElementTree(include_parse)
ET.indent(include_tree, space=" ")
- include_tree.write(file,
- encoding="ISO-8859-1",
- xml_declaration=False,
- pretty_print=True)
+ include_tree.write(
+ file,
+ encoding="ISO-8859-1",
+ xml_declaration=False,
+ pretty_print=True,
+ )
parent_element.remove(self.include_elements[i])
- def _get_root(self, remove_blank_text=False, remove_comments=False):
- parser = ET.XMLParser(remove_blank_text=remove_blank_text, remove_comments=remove_comments, huge_tree=True)
+ def _get_root(
+ self, remove_blank_text: bool = False, remove_comments: bool = False
+ ) -> ET.Element:
+ parser = ET.XMLParser(
+ remove_blank_text=remove_blank_text,
+ remove_comments=remove_comments,
+ huge_tree=True,
+ )
if self.tree is None:
if self.inputfile is not None:
- self.tree = ET.parse(self.inputfile, parser)
+ self.tree = ET.parse(str(self.inputfile), parser)
else:
- raise RuntimeError("This should not happen.")
- #self.build_tree()
+ msg = "This should not happen."
+ raise RuntimeError(msg)
+ # self.build_tree()
root = self.tree.getroot()
all_occurrences = root.findall(".//include")
for occurrence in all_occurrences:
- self.include_files.append(os.path.join(self.folder, occurrence.attrib["file"]))
- for i, occurrence in enumerate(all_occurrences):
- _tree = ET.parse(self.include_files[i], parser)
+ self.include_files.append(occurrence.attrib["file"])
+ for i, _ in enumerate(all_occurrences):
+ _tree = ET.parse(str(self.folder / self.include_files[i]), parser)
_root = _tree.getroot()
parentelement = all_occurrences[i].getparent()
children_before = parentelement.getchildren()
@@ -143,10 +181,15 @@ def _get_root(self, remove_blank_text=False, remove_comments=False):
self.include_elements.append(child)
return root
- def _remove_empty_elements(self):
+ def _remove_empty_elements(self) -> None:
root = self._get_root()
empty_text_list = ["./geometry", "./python_script"]
- empty_el_list = ["./time_loop/global_process_coupling", "./curves", "./media"]
+ empty_el_list = [
+ "./time_loop/global_process_coupling",
+ "./curves",
+ "./media",
+ "./local_coordinate_system",
+ ]
for element in empty_text_list:
entry = root.find(element)
if entry is not None:
@@ -155,44 +198,45 @@ def _remove_empty_elements(self):
self.remove_element(".", tag=entry.tag, text=None)
for element in empty_el_list:
entry = root.find(element)
- if entry is not None:
- if len(entry.getchildren()) == 0:
- entry.getparent().remove(entry)
+ if (entry is not None) and (len(entry.getchildren()) == 0):
+ entry.getparent().remove(entry)
@classmethod
- def _get_parameter_pointer(cls, root, name, xpath):
+ def _get_parameter_pointer(
+ cls, root: ET.Element, name: str, xpath: str
+ ) -> ET.Element:
params = root.findall(xpath)
parameterpointer = None
for parameter in params:
for paramproperty in parameter:
- if paramproperty.tag == "name":
- if paramproperty.text == name:
- parameterpointer = parameter
+ if (paramproperty.tag == "name") and (
+ paramproperty.text == name
+ ):
+ parameterpointer = parameter
if parameterpointer is None:
- print("Parameter/Property not found")
- raise RuntimeError
+ msg = "Parameter/Property not found"
+ raise RuntimeError(msg)
return parameterpointer
@classmethod
- def _get_medium_pointer(cls, root, mediumid):
+ def _get_medium_pointer(cls, root: ET.Element, mediumid: int) -> ET.Element:
xpathmedia = "./media/medium"
mediae = root.findall(xpathmedia)
mediumpointer = None
for medium in mediae:
try:
- if medium.attrib['id'] == str(mediumid):
+ if medium.attrib["id"] == str(mediumid):
mediumpointer = medium
except KeyError:
- if len(mediae) == 1:
- if str(mediumid) == "0":
- mediumpointer = medium
+ if (len(mediae) == 1) and (str(mediumid) == "0"):
+ mediumpointer = medium
if mediumpointer is None:
- print("Medium not found")
- raise RuntimeError
+ msg = "Medium not found"
+ raise RuntimeError(msg)
return mediumpointer
@classmethod
- def _get_phase_pointer(cls, root, phase):
+ def _get_phase_pointer(cls, root: ET.Element, phase: str) -> ET.Element:
phases = root.findall("./phases/phase")
phasetypes = root.findall("./phases/phase/type")
phasecounter = None
@@ -201,12 +245,14 @@ def _get_phase_pointer(cls, root, phase):
phasecounter = i
phasepointer = phases[phasecounter]
if phasepointer is None:
- print("Phase not found")
- raise RuntimeError
+ msg = "Phase not found"
+ raise RuntimeError(msg)
return phasepointer
@classmethod
- def _get_component_pointer(cls, root, component):
+ def _get_component_pointer(
+ cls, root: ET.Element, component: str
+ ) -> ET.Element:
components = root.findall("./components/component")
componentnames = root.findall("./components/component/name")
componentcounter = None
@@ -215,21 +261,32 @@ def _get_component_pointer(cls, root, component):
componentcounter = i
componentpointer = components[componentcounter]
if componentpointer is None:
- print("Component not found")
- raise RuntimeError
+ msg = "Component not found"
+ raise RuntimeError(msg)
return componentpointer
@classmethod
- def _set_type_value(cls, parameterpointer, value, parametertype, valuetag=None):
+ def _set_type_value(
+ cls,
+ parameterpointer: ET.Element,
+ value: int,
+ parametertype: Any | None,
+ valuetag: str | None = None,
+ ) -> None:
for paramproperty in parameterpointer:
- if paramproperty.tag == valuetag:
- if not value is None:
- paramproperty.text = str(value)
- elif paramproperty.tag == "type":
- if not parametertype is None:
- paramproperty.text = str(parametertype)
-
- def add_element(self, parent_xpath="./", tag=None, text=None, attrib_list=None, attrib_value_list=None):
+ if (paramproperty.tag == valuetag) and (value is not None):
+ paramproperty.text = str(value)
+ elif paramproperty.tag == "type" and parametertype is not None:
+ paramproperty.text = str(parametertype)
+
+ def add_element(
+ self,
+ parent_xpath: str = "./",
+ tag: str | None = None,
+ text: str | None = None,
+ attrib_list: Any | None = None,
+ attrib_value_list: Any | None = None,
+ ) -> None:
"""General method to add an Entry
An element is a single tag containing 'text',
@@ -251,22 +308,24 @@ def add_element(self, parent_xpath="./", tag=None, text=None, attrib_list=None,
root = self._get_root()
parents = root.findall(parent_xpath)
for parent in parents:
- if not tag is None:
+ if tag is not None:
q = ET.SubElement(parent, tag)
- if not text is None:
+ if text is not None:
q.text = str(text)
- if not attrib_list is None:
+ if attrib_list is not None:
if attrib_value_list is None:
- print("attrib_value_list is not given for add_element")
- raise RuntimeError
+ msg = "attrib_value_list is not given for add_element"
+ raise RuntimeError(msg)
if len(attrib_list) != len(attrib_value_list):
- print("The size of attrib_list is not the same as that of attrib_value_list")
- raise RuntimeError
+ msg = "The size of attrib_list is not the same as that of attrib_value_list"
+ raise RuntimeError(msg)
- for attrib, attrib_value in zip (attrib_list, attrib_value_list):
+ for attrib, attrib_value in zip(
+ attrib_list, attrib_value_list, strict=False
+ ):
q.set(attrib, attrib_value)
- def add_include(self, parent_xpath="./", file=""):
+ def add_include(self, parent_xpath: str = "./", file: str = "") -> None:
"""add include element
Parameters
@@ -276,17 +335,24 @@ def add_include(self, parent_xpath="./", file=""):
file : `str`
file name
"""
- self.add_includes.append({'parent_xpath': parent_xpath, 'file': file})
+ self.add_includes.append({"parent_xpath": parent_xpath, "file": file})
- def _add_includes(self, root):
+ def _add_includes(self, root: ET.Element) -> None:
for add_include in self.add_includes:
- parent = root.findall(add_include['parent_xpath'])
+ parent = root.findall(add_include["parent_xpath"])
newelement = []
for i, entry in enumerate(parent):
newelement.append(ET.SubElement(entry, "include"))
- newelement[i].set("file", add_include['file'])
-
- def add_block(self, blocktag, block_attrib=None, parent_xpath="./", taglist=None, textlist=None):
+ newelement[i].set("file", add_include["file"])
+
+ def add_block(
+ self,
+ blocktag: str,
+ block_attrib: Any | None = None,
+ parent_xpath: str = "./",
+ taglist: list[str] | None = None,
+ textlist: list[str] | None = None,
+ ) -> None:
"""General method to add a Block
A block consists of an enclosing tag containing a number of
@@ -297,26 +363,31 @@ def add_block(self, blocktag, block_attrib=None, parent_xpath="./", taglist=None
blocktag : `str`
name of the enclosing tag
block_attrib : 'dict', optional
+ attributes belonging to the blocktag
parent_xpath : `str`, optional
XPath of the parent tag
taglist : `list`
list of strings containing the keys
textlist : `list`
list of strings, ints or floats retaining the corresponding values
+
"""
root = self._get_root()
parents = root.findall(parent_xpath)
for parent in parents:
q = ET.SubElement(parent, blocktag)
- if not block_attrib is None:
+ if block_attrib is not None:
for key, val in block_attrib.items():
- q.set(key,val)
- for i, tag in enumerate(taglist):
- r = ET.SubElement(q, tag)
- if not textlist[i] is None:
- r.text = str(textlist[i])
-
- def deactivate_property(self, name, mediumid=None, phase=None):
+ q.set(key, val)
+ if (taglist is not None) and (textlist is not None):
+ for i, tag in enumerate(taglist):
+ r = ET.SubElement(q, tag)
+ if textlist[i] is not None:
+ r.text = str(textlist[i])
+
+ def deactivate_property(
+ self, name: str, mediumid: int = 0, phase: str | None = None
+ ) -> None:
"""Replaces MPL properties by a comment
Parameters
@@ -324,20 +395,27 @@ def deactivate_property(self, name, mediumid=None, phase=None):
mediumid : `int`
id of the medium
phase : `str`
+ name of the phase
name : `str`
property name
"""
root = self._get_root()
mediumpointer = self._get_medium_pointer(root, mediumid)
- phasepointer = self._get_phase_pointer(mediumpointer, phase)
xpathparameter = "./properties/property"
if phase is None:
- parameterpointer = self._get_parameter_pointer(mediumpointer, name, xpathparameter)
+ parameterpointer = self._get_parameter_pointer(
+ mediumpointer, name, xpathparameter
+ )
else:
- parameterpointer = self._get_parameter_pointer(phasepointer, name, xpathparameter)
- parameterpointer.getparent().replace(parameterpointer, ET.Comment(ET.tostring(parameterpointer)))
-
- def deactivate_parameter(self, name):
+ phasepointer = self._get_phase_pointer(mediumpointer, phase)
+ parameterpointer = self._get_parameter_pointer(
+ phasepointer, name, xpathparameter
+ )
+ parameterpointer.getparent().replace(
+ parameterpointer, ET.Comment(ET.tostring(parameterpointer))
+ )
+
+ def deactivate_parameter(self, name: str) -> None:
"""Replaces parameters by a comment
Parameters
@@ -347,10 +425,16 @@ def deactivate_parameter(self, name):
"""
root = self._get_root()
parameterpath = "./parameters/parameter"
- parameterpointer = self._get_parameter_pointer(root, name, parameterpath)
- parameterpointer.getparent().replace(parameterpointer, ET.Comment(ET.tostring(parameterpointer)))
-
- def remove_element(self, xpath, tag = None, text = None):
+ parameterpointer = self._get_parameter_pointer(
+ root, name, parameterpath
+ )
+ parameterpointer.getparent().replace(
+ parameterpointer, ET.Comment(ET.tostring(parameterpointer))
+ )
+
+ def remove_element(
+ self, xpath: str, tag: str | None = None, text: str | None = None
+ ) -> None:
"""Removes an element
Parameters
@@ -369,7 +453,9 @@ def remove_element(self, xpath, tag = None, text = None):
if sub_element.tag == tag and sub_element.text == text:
sub_element.getparent().remove(sub_element)
- def replace_text(self, value, xpath=".", occurrence=-1):
+ def replace_text(
+ self, value: str | int, xpath: str = ".", occurrence: int = -1
+ ) -> None:
"""General method for replacing text between opening and closing tags
@@ -380,19 +466,22 @@ def replace_text(self, value, xpath=".", occurrence=-1):
xpath : `str`, optional
XPath of the tag
occurrence : `int`, optional
- Easy way to adress nonunique XPath addresses by their occurence
+ Easy way to address nonunique XPath addresses by their occurrence
from the top of the XML file
Default: -1
"""
root = self._get_root()
find_xpath = root.findall(xpath)
for i, entry in enumerate(find_xpath):
- if occurrence < 0:
- entry.text = str(value)
- elif i == occurrence:
+ if occurrence < 0 or i == occurrence:
entry.text = str(value)
- def replace_block_by_include(self, xpath="./", filename="include.xml", occurrence=0):
+ def replace_block_by_include(
+ self,
+ xpath: str = "./",
+ filename: str = "include.xml",
+ occurrence: int = 0,
+ ) -> None:
"""General method for replacing a block by an include
@@ -401,20 +490,22 @@ def replace_block_by_include(self, xpath="./", filename="include.xml", occurrenc
xpath : `str`, optional
XPath of the tag
filename : `str`, optional
+ name of the include file
occurrence : `int`, optional
Addresses nonunique XPath by their occurece
- Default: 0
"""
- print("Note: Includes are only written if write_input(keep_includes=True) is called.")
+ print(
+ "Note: Includes are only written if write_input(keep_includes=True) is called."
+ )
root = self._get_root()
find_xpath = root.findall(xpath)
for i, entry in enumerate(find_xpath):
if i == occurrence:
self.include_elements.append(entry)
- self.include_files.append(os.path.join(self.folder, filename))
+ self.include_files.append(self.prjfile.parent / filename)
- def replace_mesh(self, oldmesh, newmesh):
- """ Method to replace meshes
+ def replace_mesh(self, oldmesh: str, newmesh: str) -> None:
+ """Method to replace meshes
Parameters
----------
@@ -423,24 +514,31 @@ def replace_mesh(self, oldmesh, newmesh):
"""
root = self._get_root()
bulkmesh = root.find("./mesh")
- try:
+ if bulkmesh is not None:
if bulkmesh.text == oldmesh:
bulkmesh.text = newmesh
- except:
- pass
+ else:
+ msg = "Bulk mesh name and oldmesh argument don't agree."
+ raise RuntimeError(msg)
all_occurrences_meshsection = root.findall("./meshes/mesh")
for occurrence in all_occurrences_meshsection:
if occurrence.text == oldmesh:
occurrence.text = newmesh
all_occurrences = root.findall(".//mesh")
for occurrence in all_occurrences:
- if not occurrence in all_occurrences_meshsection:
- oldmesh_stripped = os.path.split(oldmesh)[1].replace(".vtu","")
- newmesh_stripped = os.path.split(newmesh)[1].replace(".vtu","")
+ if occurrence not in all_occurrences_meshsection:
+ oldmesh_stripped = os.path.split(oldmesh)[1].replace(".vtu", "")
+ newmesh_stripped = os.path.split(newmesh)[1].replace(".vtu", "")
if occurrence.text == oldmesh_stripped:
occurrence.text = newmesh_stripped
- def replace_parameter(self, name=None, parametertype=None, taglist=None, textlist=None):
+ def replace_parameter(
+ self,
+ name: str = "",
+ parametertype: str = "",
+ taglist: list[str] | None = None,
+ textlist: list[str] | None = None,
+ ) -> None:
"""Replacing parametertypes and values
Parameters
@@ -455,20 +553,24 @@ def replace_parameter(self, name=None, parametertype=None, taglist=None, textlis
values of parameter
"""
root = self._get_root()
- parameterpath = "./parameters/parameter[name=\'"+name+"\']"
+ parameterpath = "./parameters/parameter[name='" + name + "']"
parent = root.find(parameterpath)
children = parent.getchildren()
for child in children:
- if not child.tag in ["name","type"]:
+ if child.tag not in ["name", "type"]:
self.remove_element(f"{parameterpath}/{child.tag}")
paramtype = root.find(f"{parameterpath}/type")
paramtype.text = parametertype
- for i, tag in enumerate(taglist):
- if not tag in ["name","type"]:
- self.add_element(parent_xpath=parameterpath,
- tag=tag, text=textlist[i])
-
- def replace_parameter_value(self, name=None, value=None, valuetag="value"):
+ if (taglist is not None) and (textlist is not None):
+ for i, tag in enumerate(taglist):
+ if tag not in ["name", "type"]:
+ self.add_element(
+ parent_xpath=parameterpath, tag=tag, text=textlist[i]
+ )
+
+ def replace_parameter_value(
+ self, name: str = "", value: int = 0, valuetag: str = "value"
+ ) -> None:
"""Replacing parameter values
Parameters
@@ -485,11 +587,21 @@ def replace_parameter_value(self, name=None, value=None, valuetag="value"):
"""
root = self._get_root()
parameterpath = "./parameters/parameter"
- parameterpointer = self._get_parameter_pointer(root, name, parameterpath)
+ parameterpointer = self._get_parameter_pointer(
+ root, name, parameterpath
+ )
self._set_type_value(parameterpointer, value, None, valuetag=valuetag)
- def replace_phase_property_value(self, mediumid=None, phase="AqueousLiquid", component=None, name=None, value=None,
- propertytype=None, valuetag="value"):
+ def replace_phase_property_value(
+ self,
+ mediumid: int = 0,
+ phase: str = "AqueousLiquid",
+ component: str | None = None,
+ name: str = "",
+ value: int = 0,
+ propertytype: str = "Constant",
+ valuetag: str = "value",
+ ) -> None:
"""Replaces properties in medium phases
Parameters
@@ -499,6 +611,7 @@ def replace_phase_property_value(self, mediumid=None, phase="AqueousLiquid", com
phase : `str`
name of the phase
component : `str`
+ name of the component
name : `str`
property name
value : `str`/any
@@ -515,11 +628,21 @@ def replace_phase_property_value(self, mediumid=None, phase="AqueousLiquid", com
if component is not None:
phasepointer = self._get_component_pointer(phasepointer, component)
xpathparameter = "./properties/property"
- parameterpointer = self._get_parameter_pointer(phasepointer, name, xpathparameter)
- self._set_type_value(parameterpointer, value, propertytype, valuetag=valuetag)
-
- def replace_medium_property_value(self, mediumid=None, name=None, value=None, propertytype=None,
- valuetag="value"):
+ parameterpointer = self._get_parameter_pointer(
+ phasepointer, name, xpathparameter
+ )
+ self._set_type_value(
+ parameterpointer, value, propertytype, valuetag=valuetag
+ )
+
+ def replace_medium_property_value(
+ self,
+ mediumid: int = 0,
+ name: str = "",
+ value: int = 0,
+ propertytype: str = "Constant",
+ valuetag: str = "value",
+ ) -> None:
"""Replaces properties in medium (not belonging to any phase)
Parameters
@@ -539,36 +662,45 @@ def replace_medium_property_value(self, mediumid=None, name=None, value=None, pr
root = self._get_root()
mediumpointer = self._get_medium_pointer(root, mediumid)
xpathparameter = "./properties/property"
- parameterpointer = self._get_parameter_pointer(mediumpointer, name, xpathparameter)
- self._set_type_value(parameterpointer, value, propertytype, valuetag=valuetag)
-
- def set(self, **args):
+ parameterpointer = self._get_parameter_pointer(
+ mediumpointer, name, xpathparameter
+ )
+ self._set_type_value(
+ parameterpointer, value, propertytype, valuetag=valuetag
+ )
+
+ def set(self, **args: str | int) -> None:
"""
Sets directly a uniquely defined property
List of properties is given in the dictory below
"""
property_db = {
- "t_initial": "./time_loop/processes/process/time_stepping/t_initial",
- "t_end": "./time_loop/processes/process/time_stepping/t_end",
- "output_prefix": "./time_loop/output/prefix",
- "reltols": "./time_loop/processes/process/convergence_criterion/reltols",
- "abstols": "./time_loop/processes/process/convergence_criterion/abstols",
- "mass_lumping": "./processes/process/mass_lumping",
- "eigen_solver": "./linear_solvers/linear_solver/eigen/solver_type",
- "eigen_precon": "./linear_solvers/linear_solver/eigen/precon_type",
- "eigen_max_iteration_step": "./linear_solvers/linear_solver/eigen/max_iteration_step",
- "eigen_error_tolerance": "./linear_solvers/linear_solver/eigen/error_tolerance",
- "eigen_scaling": "./linear_solvers/linear_solver/eigen/scaling",
- "petsc_prefix": "./linear_solvers/linear_solver/petsc/prefix",
- "petsc_parameters": "./linear_solvers/linear_solver/petsc/parameters",
- "compensate_displacement": "./process_variables/process_variable[name='displacement']/compensate_non_equilibrium_initial_residuum",
- "compensate_all": "./process_variables/process_variable/compensate_non_equilibrium_initial_residuum"
- }
+ "t_initial": "./time_loop/processes/process/time_stepping/t_initial",
+ "t_end": "./time_loop/processes/process/time_stepping/t_end",
+ "output_prefix": "./time_loop/output/prefix",
+ "reltols": "./time_loop/processes/process/convergence_criterion/reltols",
+ "abstols": "./time_loop/processes/process/convergence_criterion/abstols",
+ "mass_lumping": "./processes/process/mass_lumping",
+ "eigen_solver": "./linear_solvers/linear_solver/eigen/solver_type",
+ "eigen_precon": "./linear_solvers/linear_solver/eigen/precon_type",
+ "eigen_max_iteration_step": "./linear_solvers/linear_solver/eigen/max_iteration_step",
+ "eigen_error_tolerance": "./linear_solvers/linear_solver/eigen/error_tolerance",
+ "eigen_scaling": "./linear_solvers/linear_solver/eigen/scaling",
+ "petsc_prefix": "./linear_solvers/linear_solver/petsc/prefix",
+ "petsc_parameters": "./linear_solvers/linear_solver/petsc/parameters",
+ "compensate_displacement": "./process_variables/process_variable[name='displacement']/compensate_non_equilibrium_initial_residuum",
+ "compensate_all": "./process_variables/process_variable/compensate_non_equilibrium_initial_residuum",
+ }
for key, val in args.items():
self.replace_text(val, xpath=property_db[key])
-
- def restart(self, restart_suffix="_restart", t_initial=None, t_end=None, zero_displacement=False):
+ def restart(
+ self,
+ restart_suffix: str = "_restart",
+ t_initial: float | None = None,
+ t_end: float | None = None,
+ zero_displacement: bool = False,
+ ) -> None:
"""Prepares the project file for a restart.
Takes the last time step from the PVD file mentioned in the PRJ file.
@@ -588,16 +720,17 @@ def restart(self, restart_suffix="_restart", t_initial=None, t_end=None, zero_di
root_prj = self._get_root()
filetype = root_prj.find("./time_loop/output/type").text
- pvdfile = root_prj.find("./time_loop/output/prefix").text+".pvd"
- pvdfile = os.path.join(self.output_dir, pvdfile)
- if not filetype == "VTK":
- raise RuntimeError("Output fil (*args: object) Please use VTK")
- tree = ET.parse(pvdfile)
- xpath="./Collection/DataSet"
+ pvdfile = root_prj.find("./time_loop/output/prefix").text + ".pvd"
+ pvdfile = self.output_dir / pvdfile
+ if filetype != "VTK":
+ msg = "Output file type unknown. Please use VTK."
+ raise RuntimeError(msg)
+ tree = ET.parse(pvdfile)
+ xpath = "./Collection/DataSet"
root_pvd = tree.getroot()
find_xpath = root_pvd.findall(xpath)
- lastfile = find_xpath[-1].attrib['file']
- last_time = find_xpath[-1].attrib['timestep']
+ lastfile = find_xpath[-1].attrib["file"]
+ last_time = find_xpath[-1].attrib["timestep"]
try:
bulk_mesh = root_prj.find("./mesh").text
except AttributeError:
@@ -606,32 +739,65 @@ def restart(self, restart_suffix="_restart", t_initial=None, t_end=None, zero_di
except AttributeError:
print("Can't find bulk mesh.")
self.replace_mesh(bulk_mesh, lastfile)
- root_prj.find("./time_loop/output/prefix").text = root_prj.find("./time_loop/output/prefix").text + restart_suffix
- t_initials = root_prj.findall("./time_loop/processes/process/time_stepping/t_initial")
- t_ends = root_prj.findall("./time_loop/processes/process/time_stepping/t_end")
+ root_prj.find("./time_loop/output/prefix").text = (
+ root_prj.find("./time_loop/output/prefix").text + restart_suffix
+ )
+ t_initials = root_prj.findall(
+ "./time_loop/processes/process/time_stepping/t_initial"
+ )
+ t_ends = root_prj.findall(
+ "./time_loop/processes/process/time_stepping/t_end"
+ )
for i, t0 in enumerate(t_initials):
if t_initial is None:
t0.text = last_time
else:
t0.text = str(t_initial)
- if not t_end is None:
+ if t_end is not None:
t_ends[i].text = str(t_end)
- process_vars = root_prj.findall("./process_variables/process_variable/name")
- ic_names = root_prj.findall("./process_variables/process_variable/initial_condition")
+ process_vars = root_prj.findall(
+ "./process_variables/process_variable/name"
+ )
+ ic_names = root_prj.findall(
+ "./process_variables/process_variable/initial_condition"
+ )
for i, process_var in enumerate(process_vars):
if process_var.text == "displacement" and zero_displacement is True:
- print("Please make sure that epsilon_ip is removed from the VTU file before you run OGS.")
+ print(
+ "Please make sure that epsilon_ip is removed from the VTU file before you run OGS."
+ )
zero = {"1": "0", "2": "0 0", "3": "0 0 0"}
- cpnts = root_prj.find("./process_variables/process_variable[name='displacement']/components").text
- self.replace_parameter(name=ic_names[i].text, parametertype="Constant", taglist=["values"],
- textlist=[zero[cpnts]])
+ cpnts = root_prj.find(
+ "./process_variables/process_variable[name='displacement']/components"
+ ).text
+ self.replace_parameter(
+ name=ic_names[i].text,
+ parametertype="Constant",
+ taglist=["values"],
+ textlist=[zero[cpnts]],
+ )
else:
- self.replace_parameter(name=ic_names[i].text, parametertype="MeshNode", taglist=["mesh","field_name"],
- textlist=[lastfile.split("/")[-1].replace(".vtu",""), process_var.text])
+ self.replace_parameter(
+ name=ic_names[i].text,
+ parametertype="MeshNode",
+ taglist=["mesh", "field_name"],
+ textlist=[
+ lastfile.split("/")[-1].replace(".vtu", ""),
+ process_var.text,
+ ],
+ )
self.remove_element("./processes/process/initial_stress")
-
- def run_model(self, logfile="out.log", path=None, args=None, container_path=None, wrapper=None, write_logs=True, write_prj_to_pvd=True):
+ def run_model(
+ self,
+ logfile: Path = Path("out.log"),
+ path: Path | None = None,
+ args: Any | None = None,
+ container_path: Path | str | None = None,
+ wrapper: Any | None = None,
+ write_logs: bool = True,
+ write_prj_to_pvd: bool = True,
+ ) -> None:
"""Command to run OGS.
Runs OGS with the project file specified as PROJECT_FILE
@@ -654,55 +820,75 @@ def run_model(self, logfile="out.log", path=None, args=None, container_path=None
write_logs: `bolean`, optional
set False to omit logging
"""
-
- ogs_path = ""
- if self.threads is None:
- env_export = ""
- else:
- env_export = f"export OMP_NUM_THREADS={self.threads} && "
- if not container_path is None:
- container_path = os.path.expanduser(container_path)
- if os.path.isfile(container_path) is False:
- raise RuntimeError('The specific container-path is not a file. Please provide a path to the OGS container.')
- if not container_path.endswith(".sif"):
- raise RuntimeError('The specific file is not a Singularity container. Please provide a *.sif file containing OGS.')
- if not path is None:
- path = os.path.expanduser(path)
- if os.path.isdir(path) is False:
- if not container_path is None:
- raise RuntimeError('The specified path is not a directory. Please provide a directory containing the Singularity executable.')
- raise RuntimeError('The specified path is not a directory. Please provide a directory containing the OGS executable.')
- ogs_path += path
- if not logfile is None:
- self.logfile = logfile
- if not container_path is None:
+ ogs_path: Path = Path()
+ env_export = ""
+ if self.threads is not None:
+ env_export += f"export OMP_NUM_THREADS={self.threads} && "
+ if self.asm_threads is not None:
+ env_export += f"export OGS_ASM_THREADS={self.asm_threads} && "
+ if container_path is not None:
+ container_path = Path(container_path)
+ container_path = container_path.expanduser()
+ if not container_path.is_file():
+ msg = "The specific container-path is not a file. Please provide a path to the OGS container."
+ raise RuntimeError(msg)
+ if str(container_path.suffix).lower() != ".sif":
+ msg = "The specific file is not a Singularity container. Please provide a *.sif file containing OGS."
+ raise RuntimeError(msg)
+ if path:
+ path = Path(path)
+ path = path.expanduser()
+ if not path.is_dir():
+ if container_path is not None:
+ msg = "The specified path is not a directory. Please provide a directory containing the Singularity executable."
+ raise RuntimeError(msg)
+ msg = "The specified path is not a directory. Please provide a directory containing the OGS executable."
+ raise RuntimeError(msg)
+ ogs_path = ogs_path / path
+ if logfile is not None:
+ self.logfile = Path(logfile)
+ if container_path is not None:
if sys.platform == "win32":
- raise RuntimeError('Running OGS in a Singularity container is only possible in Linux. See https://sylabs.io/guides/3.0/user-guide/installation.html for Windows solutions.')
- ogs_path = os.path.join(ogs_path, "singularity")
- if shutil.which(ogs_path) is None:
- raise RuntimeError('The Singularity executable was not found. See https://www.opengeosys.org/docs/userguide/basics/container/ for installation instructions.')
+ msg = "Running OGS in a Singularity container is only possible in Linux. See https://sylabs.io/guides/3.0/user-guide/installation.html for Windows solutions."
+ raise RuntimeError(msg)
+ ogs_path = ogs_path / "singularity"
+ if shutil.which(str(ogs_path)) is None:
+ msg = "The Singularity executable was not found. See https://www.opengeosys.org/docs/userguide/basics/container/ for installation instructions."
+ raise RuntimeError(msg)
else:
if sys.platform == "win32":
- ogs_path = os.path.join(ogs_path, "ogs.exe")
+ ogs_path = ogs_path / "ogs.exe"
else:
- ogs_path = os.path.join(ogs_path, "ogs")
- if shutil.which(ogs_path) is None:
- raise RuntimeError('The OGS executable was not found. See https://www.opengeosys.org/docs/userguide/basics/introduction/ for installation instructions.')
+ ogs_path = ogs_path / "ogs"
+ if shutil.which(str(ogs_path)) is None:
+ msg = "The OGS executable was not found. See https://www.opengeosys.org/docs/userguide/basics/introduction/ for installation instructions."
+ raise RuntimeError(msg)
cmd = env_export
- if not wrapper is None:
+ if wrapper is not None:
cmd += wrapper + " "
cmd += f"{ogs_path} "
- if not container_path is None:
- if not wrapper is None:
- cmd = env_export + "singularity exec " + f"{container_path} " + wrapper + " "
+ if container_path is not None:
+ if wrapper is not None:
+ cmd = (
+ env_export
+ + "singularity exec "
+ + f"{container_path} "
+ + wrapper
+ + " "
+ )
else:
- cmd = env_export + "singularity exec " + f"{container_path} " + "ogs "
- if not args is None:
+ cmd = (
+ env_export
+ + "singularity exec "
+ + f"{container_path} "
+ + "ogs "
+ )
+ if args is not None:
argslist = args.split(" ")
output_dir_flag = False
for entry in argslist:
if output_dir_flag is True:
- self.output_dir = entry
+ self.output_dir = Path(entry)
output_dir_flag = False
if "-o" in entry:
output_dir_flag = True
@@ -713,9 +899,22 @@ def run_model(self, logfile="out.log", path=None, args=None, container_path=None
cmd += f"{self.prjfile}"
startt = time.time()
if sys.platform == "win32":
- returncode = subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
+ returncode = subprocess.run(
+ cmd,
+ shell=True,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT,
+ check=False,
+ )
else:
- returncode = subprocess.run(cmd, shell=True, executable="bash", stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
+ returncode = subprocess.run(
+ cmd,
+ shell=True,
+ executable="bash",
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT,
+ check=False,
+ )
stopt = time.time()
self.exec_time = stopt - startt
if returncode.returncode == 0:
@@ -723,48 +922,77 @@ def run_model(self, logfile="out.log", path=None, args=None, container_path=None
print(f"Execution took {self.exec_time} s")
if write_prj_to_pvd is True:
self.inputfile = self.prjfile
- self.tree = None
- root = self._get_root(remove_blank_text=True, remove_comments=True)
- prjstring = ET.tostring(root, pretty_print = True)
- prjstring = str(prjstring).replace('\r', ' ').replace('\n', ' ').replace('--','')
+ # self.tree = None # TODO: check whether this line can be safely removed
+ root = self._get_root(
+ remove_blank_text=True, remove_comments=True
+ )
+ prjstring = ET.tostring(root, pretty_print=True)
+ prjstring = (
+ str(prjstring)
+ .replace("\r", " ")
+ .replace("\n", " ")
+ .replace("--", "")
+ )
+ if self.tree is None:
+ msg = "self.tree is empty."
+ raise AttributeError(msg)
fn_type = self.tree.find("./time_loop/output/type").text
fn = None
if fn_type == "VTK":
- fn = self.tree.find("./time_loop/output/prefix").text + ".pvd"
- fn = os.path.join(self.output_dir, fn)
+ fn = (
+ self.tree.find("./time_loop/output/prefix").text
+ + ".pvd"
+ )
+ fn = self.output_dir / fn
elif fn_type == "XDMF":
prefix = self.tree.find("./time_loop/output/prefix").text
mesh = self.tree.find("./mesh")
if mesh is None:
mesh = self.tree.find("./meshes/mesh")
- prefix = os.path.join(self.output_dir, prefix)
- fn = prefix + "_" + mesh.text.split(".vtu")[0] + ".xdmf"
- if not fn is None:
+ prefix = self.output_dir / prefix
+ if mesh is not None:
+ fn = (
+ str(prefix)
+ + "_"
+ + mesh.text.split(".vtu")[0]
+ + ".xdmf"
+ )
+ else:
+ msg = "No mesh found"
+ raise AttributeError(msg)
+ if fn is not None:
tree_pvd = ET.parse(fn)
root_pvd = tree_pvd.getroot()
root_pvd.append(ET.Comment(prjstring))
- tree_pvd.write(fn, encoding="ISO-8859-1", xml_declaration=True, pretty_print=True)
+ tree_pvd.write(
+ fn,
+ encoding="ISO-8859-1",
+ xml_declaration=True,
+ pretty_print=True,
+ )
print("Project file written to output.")
else:
print(f"Error code: {returncode.returncode}")
if write_logs is False:
- raise RuntimeError('OGS execution was not successful. Please set write_logs to True to obtain more information.')
- num_lines = sum(1 for line in open(self.logfile))
- with open(self.logfile) as file:
+ msg = "OGS execution was not successful. Please set write_logs to True to obtain more information."
+ raise RuntimeError(msg)
+ with self.logfile.open() as lf:
+ num_lines = len(lf.readlines())
+ with self.logfile.open() as file:
for i, line in enumerate(file):
- if i > num_lines-10:
+ if i > num_lines - 10:
print(line)
- raise RuntimeError('OGS execution was not successful.')
+ msg = "OGS execution was not successful."
+ raise RuntimeError(msg)
-
- def write_input(self, keep_includes=False):
+ def write_input(self, keep_includes: bool = False) -> None:
"""Writes the projectfile to disk
Parameters
----------
keep_includes : `boolean`, optional
"""
- if not self.tree is None:
+ if self.tree is not None:
self._remove_empty_elements()
if keep_includes is True:
self.__replace_blocks_by_includes()
@@ -777,14 +1005,20 @@ def write_input(self, keep_includes=False):
ET.indent(self.tree, space=" ")
if self.verbose is True:
display.Display(self.tree)
- self.tree.write(self.prjfile,
- encoding="ISO-8859-1",
- xml_declaration=True,
- pretty_print=True)
- return True
- raise RuntimeError("No tree has been build.")
-
- def parse_out(self, logfile=None, filter=None, maximum_lines=None, reset_index=True):
+ self.tree.write(
+ self.prjfile,
+ encoding="ISO-8859-1",
+ xml_declaration=True,
+ pretty_print=True,
+ )
+ else:
+ msg = "No tree has been build."
+ raise RuntimeError(msg)
+
+ def parse_out(self, logfile: str | None = None,
+ filter: str | None = None,
+ maximum_lines: int | None = None,
+ reset_index: bool = True) -> pd.DataFrame:
"""Parses the logfile
Parameters
@@ -821,11 +1055,16 @@ def parse_out(self, logfile=None, filter=None, maximum_lines=None, reset_index=T
return df.reset_index()
return df
- def property_dataframe(self, mediamapping=None):
+ def property_dataframe(
+ self, mediamapping: dict[int, str] | None = None
+ ) -> pd.DataFrame:
newtree = copy.deepcopy(self.tree)
+ if (newtree is None) or (self.tree is None):
+ msg = "No tree existing."
+ raise AttributeError(msg)
root = newtree.getroot()
- property_list = []
- multidim_prop = {}
+ property_list: list[Property] = []
+ multidim_prop: dict[int, dict] = {}
numofmedia = len(self.tree.findall("./media/medium"))
if mediamapping is None:
mediamapping = {}
@@ -835,71 +1074,131 @@ def property_dataframe(self, mediamapping=None):
multidim_prop[i] = {}
## preprocessing
# write elastic properties to MPL
- for entry in newtree.findall("./processes/process/constitutive_relation"):
- medium = self._get_medium_pointer(root, entry.attrib["id"])
+ for entry in newtree.findall(
+ "./processes/process/constitutive_relation"
+ ):
+ medium = self._get_medium_pointer(root, entry.attrib.get("id", "0"))
parent = medium.find("./phases/phase[type='Solid']/properties")
taglist = ["name", "type", "parameter_name"]
for subentry in entry:
- if subentry.tag in ["youngs_modulus", "poissons_ratio","youngs_moduli", "poissons_ratios", "shear_moduli"]:
+ if subentry.tag in [
+ "youngs_modulus",
+ "poissons_ratio",
+ "youngs_moduli",
+ "poissons_ratios",
+ "shear_moduli",
+ ]:
textlist = [subentry.tag, "Parameter", subentry.text]
q = ET.SubElement(parent, "property")
for i, tag in enumerate(taglist):
r = ET.SubElement(q, tag)
- if not textlist[i] is None:
+ if textlist[i] is not None:
r.text = str(textlist[i])
for location in location_pointer:
# resolve parameters
- parameter_names_add = newtree.findall(f"./media/medium/{location_pointer[location]}properties/property[type='Parameter']/parameter_name")
+ parameter_names_add = newtree.findall(
+ f"./media/medium/{location_pointer[location]}properties/property[type='Parameter']/parameter_name"
+ )
parameter_names = [name.text for name in parameter_names_add]
for parameter_name in parameter_names:
- param_type = newtree.find(f"./parameters/parameter[name='{parameter_name}']/type").text
+ param_type = newtree.find(
+ f"./parameters/parameter[name='{parameter_name}']/type"
+ ).text
if param_type == "Constant":
- param_value = newtree.findall(f"./parameters/parameter[name='{parameter_name}']/value")
- param_value.append(newtree.find(f"./parameters/parameter[name='{parameter_name}']/values"))
- property_type = newtree.findall(f"./media/medium/{location_pointer[location]}properties/property[parameter_name='{parameter_name}']/type")
+ param_value = newtree.findall(
+ f"./parameters/parameter[name='{parameter_name}']/value"
+ )
+ param_value.append(
+ newtree.find(
+ f"./parameters/parameter[name='{parameter_name}']/values"
+ )
+ )
+ property_type = newtree.findall(
+ f"./media/medium/{location_pointer[location]}properties/property[parameter_name='{parameter_name}']/type"
+ )
for entry in property_type:
entry.text = "Constant"
- property_value = newtree.findall(f"./media/medium/{location_pointer[location]}properties/property[parameter_name='{parameter_name}']/parameter_name")
+ property_value = newtree.findall(
+ f"./media/medium/{location_pointer[location]}properties/property[parameter_name='{parameter_name}']/parameter_name"
+ )
for entry in property_value:
entry.tag = "value"
entry.text = param_value[0].text
# expand tensors
expand_tensors(self, numofmedia, multidim_prop, root, location)
expand_van_genuchten(self, numofmedia, root, location)
- property_names = [name.text for name in newtree.findall(f"./media/medium/{location_pointer[location]}properties/property/name")]
+ property_names = [
+ name.text
+ for name in newtree.findall(
+ f"./media/medium/{location_pointer[location]}properties/property/name"
+ )
+ ]
property_names = list(dict.fromkeys(property_names))
- values = {}
+ values: dict[str, list] = {}
for name in property_names:
values[name] = []
- orig_name = ''.join(c for c in name if not c.isnumeric())
- number_suffix = ''.join(c for c in name if c.isnumeric())
+ orig_name = "".join(c for c in name if not c.isnumeric())
+ number_suffix = "".join(c for c in name if c.isnumeric())
if orig_name in property_dict[location]:
for medium_id in range(numofmedia):
if medium_id in mediamapping:
medium = self._get_medium_pointer(root, medium_id)
- proptytype = medium.find(f"./{location_pointer[location]}properties/property[name='{name}']/type")
+ proptytype = medium.find(
+ f"./{location_pointer[location]}properties/property[name='{name}']/type"
+ )
if proptytype is None:
- values[name].append(Value(mediamapping[medium_id],None))
+ values[name].append(
+ Value(mediamapping[medium_id], None)
+ )
else:
- if "Constant" == proptytype.text:
- value_entry = medium.find(f"./{location_pointer[location]}properties/property[name='{name}']/value").text
+ if proptytype.text == "Constant":
+ value_entry = medium.find(
+ f"./{location_pointer[location]}properties/property[name='{name}']/value"
+ ).text
value_entry_list = value_entry.split(" ")
if len(value_entry_list) == 1:
- values[name].append(Value(mediamapping[medium_id],float(value_entry)))
+ values[name].append(
+ Value(
+ mediamapping[medium_id],
+ float(value_entry),
+ )
+ )
else:
- values[name].append(Value(mediamapping[medium_id],None))
- if not number_suffix == "":
- new_symbol = property_dict[location][orig_name]["symbol"][:-1]+"_"+number_suffix +"$"
+ values[name].append(
+ Value(mediamapping[medium_id], None)
+ )
+ if number_suffix != "":
+ new_symbol = (
+ property_dict[location][orig_name]["symbol"][:-1]
+ + "_"
+ + number_suffix
+ + "$"
+ )
else:
- new_symbol = property_dict[location][orig_name]["symbol"]
- property_list.append(Property(property_dict[location][orig_name]["title"], new_symbol, property_dict[location][orig_name]["unit"], values[name]))
+ new_symbol = property_dict[location][orig_name][
+ "symbol"
+ ]
+ property_list.append(
+ Property(
+ property_dict[location][orig_name]["title"],
+ new_symbol,
+ property_dict[location][orig_name]["unit"],
+ values[name],
+ )
+ )
properties = PropertySet(property=property_list)
return pd.DataFrame(properties)
- def write_property_latextable(self, latexfile="property_dataframe.tex", mediamapping=None, float_format="{:.2e}"):
- with open(latexfile, "w") as tf:
- tf.write(self.property_dataframe(mediamapping).to_latex(index=False,
- float_format=float_format.format))
-
-
+ def write_property_latextable(
+ self,
+ latexfile: Path = Path("property_dataframe.tex"),
+ mediamapping: dict[int, str] | None = None,
+ float_format: str = "{:.2e}",
+ ) -> None:
+ with latexfile.open("w") as tf:
+ tf.write(
+ self.property_dataframe(mediamapping).to_latex(
+ index=False, float_format=float_format.format
+ )
+ )
diff --git a/tests/test_ogs6py.py b/tests/test_ogs6py.py
index b25ee07..5c73db3 100644
--- a/tests/test_ogs6py.py
+++ b/tests/test_ogs6py.py
@@ -632,7 +632,7 @@ def test_replace_property_in_include(self):
while chunk := f.read(8192):
file_hash.update(chunk)
self.assertEqual(file_hash.hexdigest(), 'a5ca3722007055f9c1672d1ffc8994f8')
- with open("tests/solid_inc.xml", "rb") as f:
+ with open("solid_inc.xml", "rb") as f:
file_hash = hashlib.md5()
while chunk := f.read(8192):
file_hash.update(chunk)