From e666cef0b9bfb3f78c5eb1bcee08965f71d6f2b8 Mon Sep 17 00:00:00 2001 From: Florian Zill <florian.zill@ufz.de> Date: Tue, 18 Jul 2023 13:44:57 +0000 Subject: [PATCH] docu for propertylib --- docs/_static/ogstools.css | 4 + docs/conf.py | 7 ++ docs/examples/howto_propertylib/README.rst | 6 ++ .../howto_propertylib/plot_propertylib.py | 77 +++++++++++++++++++ ogstools/meshplotlib/core.py | 35 ++++++--- .../physics/nuclearwasteheat/nuclearwaste.py | 5 +- ogstools/propertylib/__init__.py | 17 ++-- ogstools/propertylib/_uncoupled.py | 50 ++++-------- ogstools/propertylib/defaults.py | 29 +++++++ ogstools/propertylib/property.py | 42 +++++++--- ogstools/propertylib/property_collection.py | 35 ++++++--- ogstools/propertylib/vector2scalar.py | 8 +- pyproject.toml | 2 + tests/test_nuclearwasteheat.py | 16 ++-- tests/test_propertylib.py | 32 ++++---- 15 files changed, 263 insertions(+), 102 deletions(-) create mode 100644 docs/examples/howto_propertylib/README.rst create mode 100644 docs/examples/howto_propertylib/plot_propertylib.py create mode 100644 ogstools/propertylib/defaults.py diff --git a/docs/_static/ogstools.css b/docs/_static/ogstools.css index 5d2f68352..5c4c77d06 100644 --- a/docs/_static/ogstools.css +++ b/docs/_static/ogstools.css @@ -5,3 +5,7 @@ nav.bd-links li>a { .navbar-brand img { height: 50px; } + +table.dataframe { + width: auto; +} diff --git a/docs/conf.py b/docs/conf.py index c3f7575a4..21fe64c52 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,6 +21,7 @@ version = release = ogstools.__version__ extensions = [ "sphinx.ext.autodoc", "sphinx.ext.autodoc.typehints", + "sphinx.ext.viewcode", "sphinxarg.ext", "sphinxcontrib.programoutput", "myst_nb", @@ -84,6 +85,12 @@ sphinx_gallery_conf = { "download_all_examples": False, } +autoclass_content = "both" +autodoc_class_signature = "separated" +autodoc_member_order = "bysource" +autodoc_preserve_defaults = True +autodoc_typehints = "description" + # Suppress sphinx warning for multiple documents generated by sphinx-gallery # May break myst-nb? diff --git a/docs/examples/howto_propertylib/README.rst b/docs/examples/howto_propertylib/README.rst new file mode 100644 index 000000000..ef958cb86 --- /dev/null +++ b/docs/examples/howto_propertylib/README.rst @@ -0,0 +1,6 @@ +Features of propertylib +======================= + +.. sectionauthor:: Florian Zill (Helmholtz Centre for Environmental Research GmbH - UFZ) + +The following jupyter notebook shows some example usage of the propertylib submodule. diff --git a/docs/examples/howto_propertylib/plot_propertylib.py b/docs/examples/howto_propertylib/plot_propertylib.py new file mode 100644 index 000000000..038f41e43 --- /dev/null +++ b/docs/examples/howto_propertylib/plot_propertylib.py @@ -0,0 +1,77 @@ +""" +Features of propertylib +===================================== + +.. sectionauthor:: Florian Zill (Helmholtz Centre for Environmental Research GmbH - UFZ) + +``propertylib`` provides a common interface for other modules to structure +reading, conversion and output of mesh data. +""" + +# %% + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + +import ogstools.propertylib as ptl + +# %% +# There are some predefined default properties: + +tab = pd.DataFrame(ptl.defaults.all_properties).set_index("output_name") +tab["type"] = [type(p).__name__ for p in ptl.defaults.all_properties] +tab.drop(["tag", "func"], axis=1).sort_values(["mask", "data_name"]) + +# %% +# You can access properties either form the entire collection or from a subset +# which only contains properties available to a specific OGS process. +# Calling a property converts the argument from data_unit to output_unit and +# applies a function if specified. + +print(ptl.defaults.temperature(273.15)) # access from the entire collection +print(ptl.M.strain(0.01)) # access from Mechanics collection + +# %% +# Available processes are: + +print([type(p).__name__ for p in ptl.processes]) + +# %% +# VectorProperties and MatrixProperties contain other Properties which represent +# the result of an applied function on itself. Components can be accessed with +# brackets. VectorProperties should be of length 2 or 3 corresponding to the +# dimension. MatrixProperties likewise should be of length 4 [xx, yy, zz, xy] +# or 6 [xx, yy, zz, xy, yz, xz]. + +# %% +# Element 1 (counting from 0) of a 3D displacement vector: + +print(ptl.M.displacement[1]([0.01, 0.02, 0.03])) + +# %% +# Magnitude of a 2D displacement vector from: + +print(ptl.M.displacement.magnitude([0.03, 0.04])) + +# %% +# Log of Magnitude of a 2D velocity vector from the Hydraulics collection: +print(ptl.H.velocity.log_magnitude(np.sqrt([50, 50]))) + +# %% +# Magnitude and trace of a 3D strain matrix: +eps = np.array([1, 3, 9, 1, 2, 2]) * 1e-2 +print(ptl.M.strain.magnitude(eps)) +print(ptl.M.strain.trace(eps)) + +# %% +# You can change the attributes of the defaults. +# For example for temperature from the Thermal Collection from the default +# output_unit °C to °F: + +temp = np.linspace(273.15, 373.15, 10) +fig, axs = plt.subplots(2) +axs[0].plot(ptl.T.temperature(temp), color="r") +ptl.defaults.temperature.output_unit = "°F" +axs[1].plot(ptl.T.temperature(temp), color="b") +fig.show() diff --git a/ogstools/meshplotlib/core.py b/ogstools/meshplotlib/core.py index 2f65c3291..f6a26753d 100644 --- a/ogstools/meshplotlib/core.py +++ b/ogstools/meshplotlib/core.py @@ -13,7 +13,8 @@ from matplotlib import patches as mpatches from matplotlib import pyplot as plt from matplotlib import ticker as mticker -from ogstools.propertylib import ScalarProperty as Scalar +from ogstools.propertylib import MatrixProperty as Matrix +from ogstools.propertylib import Property from ogstools.propertylib import VectorProperty as Vector from . import image_tools, setup @@ -21,8 +22,6 @@ from . import plot_features as pf from .levels import get_levels from .mesh import Mesh -Property = Union[Scalar, Vector] - def xin_cell_data(mesh: pv.UnstructuredGrid, property: Property) -> bool: """Determine if the property is exclusive in cell data.""" @@ -43,7 +42,7 @@ def get_data(mesh: pv.UnstructuredGrid, property: Property) -> pv.DataSet: def get_cmap_norm( - levels: np.ndarray, property: Scalar, cell_data: bool + levels: np.ndarray, property: Property, cell_data: bool ) -> tuple[mcolors.Colormap, mcolors.Normalize]: """Construct a discrete colormap and norm for the property field.""" vmin, vmax = (levels[0], levels[-1]) @@ -99,7 +98,11 @@ def plot_isometric( get_data(mesh, property).active_scalars_name = property.data_name # data = get_data(mesh, property)[property.data_name] - _p_val = property.magnitude if isinstance(property, Vector) else property + _p_val = ( + property.magnitude + if isinstance(property, (Vector, Matrix)) + else property + ) data = get_data(mesh, property)[property.data_name] get_data(mesh, property)[property.data_name] = _p_val.values(data) @@ -129,7 +132,7 @@ def plot_isometric( def add_colorbar( fig: mfigure.Figure, - property: Scalar, + property: Property, cell_data: bool, cmap: mcolors.Colormap, norm: mcolors.Normalize, @@ -227,14 +230,18 @@ def subplot( # get projection mean_normal = np.abs(np.mean(mesh.extract_surface().cell_normals, axis=0)) - projection = np.argmax(mean_normal) + projection = int(np.argmax(mean_normal)) x_id, y_id = np.delete([0, 1, 2], projection) # faces contains a padding indicating number of points per face which gets # removed with this reshaping and slicing to get the array of tri's x, y = setup.length.values(surf_tri.points.T[[x_id, y_id]]) tri = surf_tri.faces.reshape((-1, 4))[:, 1:] - _property = property.magnitude if isinstance(property, Vector) else property + _property = ( + property.magnitude + if isinstance(property, (Vector, Matrix)) + else property + ) values = _property.values(get_data(surf_tri, property)[property.data_name]) p_min, p_max = np.nanmin(values), np.nanmax(values) @@ -281,7 +288,7 @@ def subplot( sec_id = np.argmax(np.delete(mean_normal, projection)) sec_labels = [] for tick in ax.get_xticks(): - origin = mesh.center + origin = np.array(mesh.center) origin[sec_id] = min( max(tick, mesh.bounds[2 * sec_id] + 1e-6), mesh.bounds[2 * sec_id + 1] - 1e-6, @@ -301,7 +308,7 @@ def subplot( def plot( - meshes: Union[np.ndarray[Mesh], Mesh], property: Property + meshes: Union[list[Mesh], np.ndarray], property: Property ) -> mfigure.Figure: """ Plot the property field of meshes with default settings. @@ -330,9 +337,13 @@ def plot( figsize=figsize, ) fig.patch.set_alpha(1) - axs: np.ndarray[plt.Axes] = np.reshape(_axs, [len(meshes), len(meshes[0])]) + axs: np.ndarray = np.reshape(_axs, [len(meshes), len(meshes[0])]) - _p_val = property.magnitude if isinstance(property, Vector) else property + _p_val = ( + property.magnitude + if isinstance(property, (Vector, Matrix)) + else property + ) p_min, p_max, n_values = np.inf, -np.inf, 0 for mesh in np.ravel(meshes): if get_data(mesh, property) is None: diff --git a/ogstools/physics/nuclearwasteheat/nuclearwaste.py b/ogstools/physics/nuclearwasteheat/nuclearwaste.py index 60f5b663f..ae74ad974 100644 --- a/ogstools/physics/nuclearwasteheat/nuclearwaste.py +++ b/ogstools/physics/nuclearwasteheat/nuclearwaste.py @@ -71,7 +71,7 @@ class Repository: "Waste inventory of the repository." @property - def time_deposit(self) -> Union[float, np.ndarray]: + def time_deposit(self) -> Union[float, list[float]]: "Deposition time for each nuclear waste type." if len(self.waste) == 1: return Q_(self.waste[0].time_deposit, units.time).magnitude @@ -94,5 +94,6 @@ class Repository: """ return np.sum( - [nw.heat(t, baseline, ncl_id) for nw in self.waste], axis=0 + np.array([nw.heat(t, baseline, ncl_id) for nw in self.waste]), + axis=0, ) diff --git a/ogstools/propertylib/__init__.py b/ogstools/propertylib/__init__.py index 6bdb2b634..f4e1d6b52 100644 --- a/ogstools/propertylib/__init__.py +++ b/ogstools/propertylib/__init__.py @@ -1,10 +1,9 @@ # Author: Florian Zill (Helmholtz Centre for Environmental Research GmbH - UFZ) """Define easy-to-access Property classes and PropertyCollection instances.""" -from . import _coupled, _uncoupled, property_collection -from .property import MatrixProperty, ScalarProperty, VectorProperty - -material_id = property_collection.PropertyCollection().material_id +from . import _coupled, _uncoupled, defaults +from .property import MatrixProperty, Property, ScalarProperty, VectorProperty +from .property_collection import PropertyCollection T = _uncoupled.T() H = _uncoupled.H() @@ -15,5 +14,13 @@ HM = _coupled.HM() TM = _coupled.TM() THM = _coupled.THM() +processes: list[PropertyCollection] = [T, H, M, TH, HM, TM, THM] + -__all__ = ["ScalarProperty", "VectorProperty", "MatrixProperty"] +__all__ = [ + "defaults", + "Property", + "ScalarProperty", + "VectorProperty", + "MatrixProperty", +] diff --git a/ogstools/propertylib/_uncoupled.py b/ogstools/propertylib/_uncoupled.py index 6fa21739a..1ca9ab35c 100644 --- a/ogstools/propertylib/_uncoupled.py +++ b/ogstools/propertylib/_uncoupled.py @@ -7,9 +7,9 @@ processes. from dataclasses import dataclass +from . import defaults from .property import MatrixProperty, ScalarProperty, VectorProperty from .property_collection import PropertyCollection -from .vector2scalar import effective_pressure, qp_ratio, von_mises @dataclass(init=False) @@ -22,12 +22,8 @@ class T(PropertyCollection): def __init__(self): """Initialize the PropertyCollection with default attributes.""" super().__init__() - self.temperature = ScalarProperty( - "temperature", "K", "°C", "temperature", "temperature_active" - ) - self.heatflowrate = ScalarProperty( - "HeatFlowRate", "", "", "HeatFlowRate", "temperature_active" - ) + self.temperature = defaults.temperature + self.heatflowrate = defaults.heatflowrate @dataclass(init=False) @@ -41,15 +37,9 @@ class H(PropertyCollection): def __init__(self): """Initialize the PropertyCollection with default attributes.""" super().__init__() - self.pressure = ScalarProperty( - "pressure", "Pa", "MPa", "pore pressure", "pressure_active" - ) - self.velocity = VectorProperty( - "velocity", "m/s", "mm/d", "darcy velocity", "pressure_active" - ) - self.massflowrate = ScalarProperty( - "MassFlowRate", "", "", "MassFlowRate", "pressure_active" - ) + self.pressure = defaults.pressure + self.velocity = defaults.velocity + self.massflowrate = defaults.massflowrate @dataclass(init=False) @@ -67,24 +57,10 @@ class M(PropertyCollection): def __init__(self): """Initialize the PropertyCollection with default attributes.""" super().__init__() - self.displacement = VectorProperty( - "displacement", "m", "mm", "displacement", "displacement_active" - ) - self.strain = MatrixProperty( - "epsilon", "", "percent", "strain", "displacement_active" - ) - self.stress = MatrixProperty( - "sigma", "Pa", "MPa", "stress", "displacement_active" - ) - self.von_mises_stress = self.stress.replace( - output_name="von Mises stress", func=von_mises - ) - self.effective_pressure = self.stress.replace( - output_name="effective pressure", func=effective_pressure - ) - self.qp_ratio = self.stress.replace( - output_name="QP ratio", output_unit="percent", func=qp_ratio - ) - self.nodal_forces = VectorProperty( - "NodalForces", "", "", "NodalForces", "displacement_active" - ) + self.displacement = defaults.displacement + self.strain = defaults.strain + self.stress = defaults.stress + self.von_mises_stress = defaults.von_mises_stress + self.effective_pressure = defaults.effective_pressure + self.qp_ratio = defaults.qp_ratio + self.nodal_forces = defaults.nodal_forces diff --git a/ogstools/propertylib/defaults.py b/ogstools/propertylib/defaults.py new file mode 100644 index 000000000..365a5554a --- /dev/null +++ b/ogstools/propertylib/defaults.py @@ -0,0 +1,29 @@ +# flake8: noqa: E501 +"Predefined properties." + +from . import vector2scalar as v2s +from .property import MatrixProperty as Matrix +from .property import Property, TagType +from .property import ScalarProperty as Scalar +from .property import VectorProperty as Vector + +T_mask = "temperature_active" +H_mask = "pressure_active" +M_mask = "displacement_active" + +# fmt: off +displacement = Vector("displacement", "m", "mm", mask=M_mask) +effective_pressure = Scalar("sigma", "Pa", "MPa", "effective pressure", M_mask, v2s.effective_pressure, TagType.unit_dim_const) +heatflowrate = Scalar("HeatFlowRate", mask=T_mask) +massflowrate = Scalar("MassFlowRate", mask=H_mask) +nodal_forces = Vector("NodalForces", mask=M_mask) +pressure = Scalar("pressure", "Pa", "MPa", "pore pressure", H_mask) +qp_ratio = Scalar("sigma", "Pa", "percent", "QP ratio", M_mask, v2s.qp_ratio) +strain = Matrix("epsilon", "", "percent", "strain", M_mask) +stress = Matrix("sigma", "Pa", "MPa", "stress", M_mask) +temperature = Scalar("temperature", "K", "°C", mask=T_mask) +velocity = Vector("velocity", "m/s", "m/s", "darcy velocity", H_mask) +von_mises_stress = Scalar("sigma", "Pa", "MPa", "von Mises stress", M_mask, v2s.von_mises, TagType.unit_dim_const) +# fmt: on + +all_properties = [v for v in locals().values() if isinstance(v, Property)] diff --git a/ogstools/propertylib/property.py b/ogstools/propertylib/property.py index 921b73d6a..1aa0e512f 100644 --- a/ogstools/propertylib/property.py +++ b/ogstools/propertylib/property.py @@ -7,7 +7,7 @@ via pint. from dataclasses import dataclass, replace from enum import Enum -from typing import Callable, Literal, Union +from typing import Any, Callable, Literal, Union import numpy as np from pint import UnitRegistry @@ -24,27 +24,39 @@ u_reg.setup_matplotlib(True) class TagType(Enum): + """Enum for property tag types.""" + mask = "mask" component = "component" unit_dim_const = "unit_dim_const" @dataclass -class ScalarProperty: - "Represent a scalar property of a dataset." +class Property: + """Represent a property of a dataset.""" data_name: str + """The name of the property data in the dataset.""" data_unit: str = "" + """The unit of the property data in the dataset.""" output_unit: str = "" + """The output unit of the property.""" output_name: str = "" + """The output name of the property.""" mask: str = "" - func: Callable[ - [Union[float, np.ndarray, PlainQuantity]], - Union[float, np.ndarray, PlainQuantity], + """The name of the mask data in the dataset.""" + func: Union[ + Callable[ + [Union[float, np.ndarray, PlainQuantity]], + Union[float, np.ndarray, PlainQuantity], + ], + Callable[[Any], Any], ] = identity + """The function to be applied on the data.""" tag: Union[ TagType, Literal["mask", "component", "unit_dim_const"], None ] = None + """A tag to signify special meanings of the property.""" def __post_init__(self): if not self.output_name: @@ -58,14 +70,14 @@ class ScalarProperty: def replace(self, **changes): """ - Create a new ScalarProperty object with modified attributes. + Create a new Property object with modified attributes. Be aware that there is no type check safety here. So make sure, the new attributes and values are correct. :param changes: Attributes to be changed. - :returns: A copy of the ScalarProperty with changed attributes. + :returns: A copy of the Property with changed attributes. """ return replace(self, **changes) @@ -122,11 +134,19 @@ class ScalarProperty: return self.tag == TagType.mask def get_mask(self): - return ScalarProperty(data_name=self.mask, tag=TagType.mask) + """ + :returns: A property representing this properties mask. + """ + return Property(data_name=self.mask, tag=TagType.mask) + + +@dataclass +class ScalarProperty(Property): + "Represent a scalar property of a dataset." @dataclass -class VectorProperty(ScalarProperty): +class VectorProperty(Property): """Represent a vector property of a dataset. Vector properties should contain either 2 (2D) or 3 (3D) components. @@ -175,7 +195,7 @@ class VectorProperty(ScalarProperty): @dataclass -class MatrixProperty(ScalarProperty): +class MatrixProperty(Property): """Represent a matrix property of a dataset. Matrix properties should contain either 4 (2D) or 6 (3D) components. diff --git a/ogstools/propertylib/property_collection.py b/ogstools/propertylib/property_collection.py index a8888f1c6..3ef8dd673 100644 --- a/ogstools/propertylib/property_collection.py +++ b/ogstools/propertylib/property_collection.py @@ -5,9 +5,10 @@ classes to group the corresponding properties. """ from dataclasses import dataclass -from typing import Union +from typing import Literal +from typing import Optional as Opt -from .property import MatrixProperty, ScalarProperty, VectorProperty +from .property import MatrixProperty, Property, ScalarProperty, VectorProperty @dataclass(init=False) @@ -24,12 +25,26 @@ class PropertyCollection: """Initialize the PropertyCollection with default attributes.""" self.material_id = ScalarProperty("MaterialIDs") - def get_properties( - self, - ) -> list[Union[ScalarProperty, VectorProperty, MatrixProperty]]: + def get_properties(self, dim: Opt[Literal[2, 3]] = None) -> list[Property]: """Return all scalar-, vector- or matrix properties.""" - return [ - v - for v in self.__dict__.values() - if isinstance(v, (ScalarProperty, VectorProperty, MatrixProperty)) - ] + props = [] + + for v in self.__dict__.values(): + if not isinstance(v, Property): + continue + props += [v] + if isinstance(v, VectorProperty) and dim in [2, 3]: + props += [v[i] for i in range(dim)] + if isinstance(v, MatrixProperty) and dim in [2, 3]: + props += [v.trace] + props += [v[i] for i in range(dim * 2)] + return props + + def find_property( + self, output_name: str, dim: Opt[Literal[2, 3]] = None + ) -> Opt[Property]: + """Return predefined property with given output_name.""" + for prop in self.get_properties(dim): + if prop.output_name == output_name: + return prop + return None diff --git a/ogstools/propertylib/vector2scalar.py b/ogstools/propertylib/vector2scalar.py index 485b55c0d..d68e7d5c1 100644 --- a/ogstools/propertylib/vector2scalar.py +++ b/ogstools/propertylib/vector2scalar.py @@ -9,7 +9,7 @@ def trace(vals: np.ndarray) -> np.ndarray: """ Calculate the trace of each vector in the input array. - :param values: The input array of vectors. + :param vals: The input array of vectors. :returns: The trace values of the vectors. """ @@ -20,7 +20,7 @@ def effective_pressure(vals: np.ndarray) -> np.ndarray: """ Calculate the effective pressure based on the input array. - :param values: The input array. + :param vals: The input array. :returns: The effective pressure values. """ @@ -31,7 +31,7 @@ def von_mises(vals: np.ndarray) -> np.ndarray: """ Calculate the von Mises stress based on the input array. - :param values: The input array. + :param vals: The input array. :returns: The von Mises stress values. """ @@ -45,7 +45,7 @@ def qp_ratio(vals: np.ndarray) -> np.ndarray: """ Calculate the QP ratio (von Mises stress / effective pressure). - :param values: The input array. + :param vals: The input array. :returns: The QP ratios. """ diff --git a/pyproject.toml b/pyproject.toml index 13e6a902a..a5500718a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ dependencies = [ "scipy>=1.10.1", "Pint>=0.22", "Pillow>=9.5.0", + "pandas>=2.0.3" ] [project.urls] @@ -110,6 +111,7 @@ extend-ignore = [ # RUF005 should be disabled when using numpy, see # https://github.com/charliermarsh/ruff/issues/2142: "RUF005", + "PT009", # can use unittest-assertion ] target-version = "py39" typing-modules = ["mypackage._compat.typing"] diff --git a/tests/test_nuclearwasteheat.py b/tests/test_nuclearwasteheat.py index cec4a657c..83c47843a 100644 --- a/tests/test_nuclearwasteheat.py +++ b/tests/test_nuclearwasteheat.py @@ -14,12 +14,16 @@ class NuclearWasteHeatTest(unittest.TestCase): """Test heat evaluation for different argument combinations.""" for model in nuclear.waste_types: for i in range(len(model.nuclide_powers)): - assert model.heat(0.0, baseline=True, ncl_id=i) - assert model.heat(0.0, baseline=True) - assert model.heat(0.0) - assert nuclear.repo_2020.heat(0.0) - assert np.all( - nuclear.repo_2020_conservative.heat(np.geomspace(1, 1e6, num=10)) + self.assertGreater(model.heat(0.0, baseline=True, ncl_id=i), 0) + self.assertGreater(model.heat(0.0, baseline=True), 0) + self.assertGreater(model.heat(0.0), 0) + self.assertGreater(nuclear.repo_2020.heat(0.0), 0) + self.assertTrue( + np.all( + nuclear.repo_2020_conservative.heat( + np.geomspace(1, 1e6, num=10) + ) + ) ) diff --git a/tests/test_propertylib.py b/tests/test_propertylib.py index ac3599bf7..3794708cb 100644 --- a/tests/test_propertylib.py +++ b/tests/test_propertylib.py @@ -5,7 +5,7 @@ import unittest import numpy as np from pint.facets.plain import PlainQuantity -from ogstools.propertylib import HM, TH, THM, TM, H, M, T, property_collection +from ogstools.propertylib import HM, TH, THM, TM, H, M, PropertyCollection, T from ogstools.propertylib.property import ScalarProperty, u_reg Q_ = u_reg.Quantity @@ -93,34 +93,36 @@ class PhysicalPropertyTest(unittest.TestCase): def test_simple(self): """Test cast functionality.""" - assert T.temperature(273.15) == Q_(0, "°C") - assert M.displacement[0]([1, 2, 3]) == Q_(1, "m") - assert M.displacement([1, 2, 3])[1] == Q_(2, "m") + self.assertEqual(T.temperature(273.15), Q_(0, "°C")) + self.assertEqual(M.displacement[0]([1, 2, 3]), Q_(1, "m")) + self.assertEqual(M.displacement([1, 2, 3])[1], Q_(2, "m")) def test_values(self): """Test values functionality.""" - assert T.temperature.values(273.15) == 0.0 + self.assertEqual(T.temperature.values(273.15), 0.0) def test_units(self): """Test get_output_unit functionality.""" - assert T.temperature.get_output_unit() == "°C" - assert H.pressure.get_output_unit() == "MPa" - assert M.strain.get_output_unit() == "%" + self.assertEqual(T.temperature.get_output_unit(), "°C") + self.assertEqual(H.pressure.get_output_unit(), "MPa") + self.assertEqual(M.strain.get_output_unit(), "%") def test_mask(self): """Test get_output_unit functionality.""" - assert ScalarProperty("pressure_active").is_component + self.assertTrue(ScalarProperty("pressure_active").is_component) def test_processes(self): """Test process attributes.""" - def data_name_set(process: property_collection.PropertyCollection): + def data_name_set(process: PropertyCollection): return {p.data_name for p in process.get_properties()} - assert data_name_set(TH) == data_name_set(T) | data_name_set(H) - assert data_name_set(HM) == data_name_set(H) | data_name_set(M) - assert data_name_set(TM) == data_name_set(T) | data_name_set(M) - assert data_name_set(THM) == data_name_set(TH) | data_name_set(M) + self.assertEqual(data_name_set(TH), data_name_set(T) | data_name_set(H)) + self.assertEqual(data_name_set(HM), data_name_set(H) | data_name_set(M)) + self.assertEqual(data_name_set(TM), data_name_set(T) | data_name_set(M)) + self.assertEqual( + data_name_set(THM), data_name_set(TH) | data_name_set(M) + ) def test_copy_ctor(self): """Test process attributes.""" @@ -134,7 +136,7 @@ class PhysicalPropertyTest(unittest.TestCase): func=M.strain.func, ) - assert M.strain == strain_copy + self.assertEqual(M.strain, strain_copy) if __name__ == "__main__": -- GitLab