Index: DamClients/DamPythonInterface/trunk/src/dampythoninterface/input.py
===================================================================
diff -u -r3487 -r3490
--- DamClients/DamPythonInterface/trunk/src/dampythoninterface/input.py (.../input.py) (revision 3487)
+++ DamClients/DamPythonInterface/trunk/src/dampythoninterface/input.py (.../input.py) (revision 3490)
@@ -23,11 +23,13 @@
from typing import List
from pathlib import Path
import lxml.etree as et
+from pydantic import validator
from .surface_line import SurfaceLine
from .soil import Soil
from .base_class import BaseDataClass
from .stability_parameters import StabilityParameters
+from .soilprofile1D import SoilProfile1D
class DamInput(BaseDataClass):
@@ -41,7 +43,22 @@
SurfaceLines: List[SurfaceLine] = []
Soils: List[Soil] = []
StabilityParameters: StabilityParameters
+ SoilProfiles1D: List[SoilProfile1D] = []
+ @validator("SoilProfiles1D")
+ def soil_profiles_contain_soils(cls, v, values, **kwargs):
+ soils_names = [soil.Name for soil in values["Soils"]]
+ soilprofiles = v
+ for soilprofile in soilprofiles:
+ for layer in soilprofile.Layers1D:
+ if not (layer.SoilName in soils_names):
+ raise ValueError(
+ f"Soil with name {layer.SoilName} In profile \
+ {soilprofile.Name}, layer {layer.Name} is not \
+ part of the Soils input"
+ )
+ return v
+
def ExportToXml(self, xml_file: Path) -> None:
"""
Function that export the DamInput dataclass to an xml that can be used as input of the DAMengine.
@@ -60,6 +77,11 @@
soils_root.append(soil.serialize_soil())
soils_aquifer.append(soil.serialize_aquifer_soil())
input_root.append(soils_root)
+ # add soil profiles to the xml file
+ soilprofiles_root = et.Element("SoilProfiles1D")
+ for soil_profile in self.SoilProfiles1D:
+ soilprofiles_root.append(soil_profile.serialize())
+ input_root.append(soilprofiles_root)
# add stability parameters to input root
input_root.append(self.StabilityParameters.serialize())
# append soil aquifers
Index: DamClients/DamPythonInterface/trunk/src/tests/test_soilprofile1D.py
===================================================================
diff -u
--- DamClients/DamPythonInterface/trunk/src/tests/test_soilprofile1D.py (revision 0)
+++ DamClients/DamPythonInterface/trunk/src/tests/test_soilprofile1D.py (revision 3490)
@@ -0,0 +1,90 @@
+# Copyright (C) Stichting Deltares 2021. All rights reserved.
+#
+# This file is part of the Dam Python Interface.
+#
+# The Dam Python Interface is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# All names, logos, and references to "Deltares" are registered trademarks of
+# Stichting Deltares and remain full property of Stichting Deltares at all times.
+# All rights reserved.
+from dampythoninterface.soilprofile1D import (
+ SoilProfile1D,
+ Layer1D,
+ WaterpressureInterpolationModelType,
+)
+
+from .utils import TestUtils
+
+import pytest
+from pathlib import Path
+from lxml import etree
+
+
+class TestSoilProfile1D:
+ def define_soil_profile(self) -> SoilProfile1D:
+ # first define the soil layers
+ layer_1 = Layer1D(
+ Name="L0",
+ SoilName="Dijkmateriaal",
+ TopLevel=10,
+ IsAquifer=False,
+ WaterpressureInterpolationModel=WaterpressureInterpolationModelType.Automatic,
+ )
+ layer_2 = Layer1D(
+ Name="L1",
+ SoilName="Deklaag_klei",
+ TopLevel=0,
+ IsAquifer=False,
+ WaterpressureInterpolationModel=WaterpressureInterpolationModelType.Automatic,
+ )
+ layer_3 = Layer1D(
+ Name="L2",
+ SoilName="wl_zand1",
+ TopLevel=-2,
+ IsAquifer=True,
+ WaterpressureInterpolationModel=WaterpressureInterpolationModelType.Automatic,
+ )
+ soil_profile = SoilProfile1D(
+ Name="soilprofile_01", BottomLevel=-10, Layers1D=[layer_1, layer_2, layer_3]
+ )
+ return soil_profile
+
+ @pytest.mark.unittest
+ def test_soil_profile_can_be_initialized(self):
+ soil_profile = self.define_soil_profile()
+ # test expectations
+ assert soil_profile.Name == "soilprofile_01"
+ assert len(soil_profile.Layers1D) == 3
+ assert soil_profile.Layers1D[-1].SoilName == "wl_zand1"
+
+ @pytest.mark.unittest
+ def test_serialize(self):
+ # initialize the stabilty parameters class
+ soil_profile = self.define_soil_profile()
+ # run test
+ root = soil_profile.serialize()
+ # test output
+ xml_output = Path(
+ TestUtils.get_output_test_data_dir(""), "test_soil_profile.xml"
+ )
+ tree = etree.ElementTree(root)
+ tree.write(str(xml_output), pretty_print=True)
+ # get template file
+ xml_test_data = Path(
+ TestUtils.get_test_data_dir("", "test_data"),
+ "test_soil_profile.xml",
+ )
+ # Line by line comparison
+ for output_file, test_file in zip(open(xml_output), open(xml_test_data)):
+ assert output_file.strip() == test_file.strip()
Index: DamClients/DamPythonInterface/trunk/src/tests/test_output/test_full_output.xml
===================================================================
diff -u -r3487 -r3490
--- DamClients/DamPythonInterface/trunk/src/tests/test_output/test_full_output.xml (.../test_full_output.xml) (revision 3487)
+++ DamClients/DamPythonInterface/trunk/src/tests/test_output/test_full_output.xml (.../test_full_output.xml) (revision 3490)
@@ -25,6 +25,14 @@
+
+
+
+
+
+
+
+
Index: DamClients/DamPythonInterface/trunk/src/tests/test_input.py
===================================================================
diff -u -r3487 -r3490
--- DamClients/DamPythonInterface/trunk/src/tests/test_input.py (.../test_input.py) (revision 3487)
+++ DamClients/DamPythonInterface/trunk/src/tests/test_input.py (.../test_input.py) (revision 3490)
@@ -20,6 +20,7 @@
# All rights reserved.
+from typing import List
import pytest
from pathlib import Path
from lxml import etree
@@ -33,12 +34,16 @@
BishopTangentLinesDefinitionType,
GridDeterminationType,
)
+from dampythoninterface.soilprofile1D import (
+ SoilProfile1D,
+ Layer1D,
+ WaterpressureInterpolationModelType,
+)
from .utils import TestUtils
class TestDamInput:
- @pytest.mark.integrationtest
- def test_ExportToXml(self):
+ def create_surface_lines(self) -> List[SurfaceLine]:
# Create surface lines
points_available = [
PointTypeEnum.SurfaceLevelOutside,
@@ -57,8 +62,9 @@
# check initial expectations
assert surfaceline_1.Name == "Surface line 1"
assert surfaceline_2.Name == "Surface line 2"
- list_of_surface_lines = [surfaceline_1, surfaceline_2]
- # create soil class
+ return [surfaceline_1, surfaceline_2]
+
+ def create_soils(self) -> List[Soil]:
soil_1 = Soil(
Name="soil 1",
AbovePhreaticLevel=17,
@@ -71,9 +77,10 @@
BelowPhreaticLevel=20,
IsAquifer=False,
)
- soils = [soil_1, soil_2]
- # Create stability parameters
- test_stabilty_parameters = StabilityParameters(
+ return [soil_1, soil_2]
+
+ def create_stability_parameters(self) -> StabilityParameters:
+ return StabilityParameters(
SearchMethod=SearchMethodType.Calculationgrid,
GridDetermination=GridDeterminationType.Automatic,
BishopTangentLinesDefinition=BishopTangentLinesDefinitionType.OnBoundaryLines,
@@ -83,11 +90,64 @@
BishopGridHorizontalPointsCount=10,
BishopGridHorizontalPointsDistance=2.5,
)
+
+ def create_profiles(self, soil_names: List[str]) -> List[SoilProfile1D]:
+ soil_layer_1 = Layer1D(
+ Name="L0",
+ SoilName=soil_names[0],
+ TopLevel=0,
+ IsAquifer=False,
+ WaterpressureInterpolationModel=WaterpressureInterpolationModelType.Automatic,
+ )
+ soil_layer_2 = Layer1D(
+ Name="L1",
+ SoilName=soil_names[1],
+ TopLevel=-2,
+ IsAquifer=False,
+ WaterpressureInterpolationModel=WaterpressureInterpolationModelType.Automatic,
+ )
+ return [
+ SoilProfile1D(
+ Name="Soil profile",
+ BottomLevel=-10,
+ Layers1D=[soil_layer_1, soil_layer_2],
+ )
+ ]
+
+ @pytest.mark.integrationtest
+ def test_soil_profiles_contain_soils(self):
+ list_of_surface_lines = self.create_surface_lines()
+ # create soil class
+ soils = self.create_soils()
+ test_stabilty_parameters = self.create_stability_parameters()
+ soil_profiles = self.create_profiles([soils[0].Name, "wrong soil name"])
+ # run test
+ error_message = "Soil with name wrong soil name"
+ with pytest.raises(ValueError) as e_info:
+ DamInput(
+ SurfaceLines=list_of_surface_lines,
+ Soils=soils,
+ StabilityParameters=test_stabilty_parameters,
+ SoilProfiles1D=soil_profiles,
+ )
+ generated_error_message = str(e_info.value)
+ assert error_message in generated_error_message
+
+ @pytest.mark.integrationtest
+ def test_ExportToXml(self):
+ # Create surface lines
+ list_of_surface_lines = self.create_surface_lines()
+ # create soil class
+ soils = self.create_soils()
+ # Create stability parameters
+ test_stabilty_parameters = self.create_stability_parameters()
+ soil_profiles = self.create_profiles([soils[0].Name, soils[1].Name])
# Make input class
model = DamInput(
SurfaceLines=list_of_surface_lines,
Soils=soils,
StabilityParameters=test_stabilty_parameters,
+ SoilProfiles1D=soil_profiles,
)
assert model
# run test
Index: DamClients/DamPythonInterface/trunk/src/tests/test_data/test_soil_profile.xml
===================================================================
diff -u
--- DamClients/DamPythonInterface/trunk/src/tests/test_data/test_soil_profile.xml (revision 0)
+++ DamClients/DamPythonInterface/trunk/src/tests/test_data/test_soil_profile.xml (revision 3490)
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
Index: DamClients/DamPythonInterface/trunk/src/dampythoninterface/soilprofile1D.py
===================================================================
diff -u
--- DamClients/DamPythonInterface/trunk/src/dampythoninterface/soilprofile1D.py (revision 0)
+++ DamClients/DamPythonInterface/trunk/src/dampythoninterface/soilprofile1D.py (revision 3490)
@@ -0,0 +1,102 @@
+# Copyright (C) Stichting Deltares 2021. All rights reserved.
+#
+# This file is part of the Dam Python Interface.
+#
+# The Dam Python Interface is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# All names, logos, and references to "Deltares" are registered trademarks of
+# Stichting Deltares and remain full property of Stichting Deltares at all times.
+# All rights reserved.
+
+
+from typing import List
+import lxml.etree as et
+from enum import IntEnum
+
+from .base_class import BaseDataClass
+
+
+class WaterpressureInterpolationModelType(IntEnum):
+ """ """
+
+ Automatic = 0
+ Hydrostatic = 1
+
+
+class Layer1D(BaseDataClass):
+ """
+ Dataclass that contains a 1D layer
+
+ :param Name: name of the layer
+ :param SoilName: soil name that is assigned in the soil layer
+ :param TopLevel: top level of the soil layer
+ :param IsAquifer: value that determines if an aquifer is contained in the layer
+ :param WaterpressureInterpolationModel: water pressure interpolation method
+
+ """
+
+ Name: str
+ SoilName: str
+ TopLevel: float
+ IsAquifer: bool
+ WaterpressureInterpolationModel: WaterpressureInterpolationModelType
+
+ def serialize(self) -> et.Element:
+ """
+ Function that serializes the Layer1D class.
+ """
+ layer1d_root = et.Element("Layer1D")
+ dictionary_of_values = self.dict()
+ layer1d_root.set("Name", dictionary_of_values.get("Name"))
+ layer1d_root.set("SoilName", dictionary_of_values.get("SoilName"))
+ layer1d_root.set("TopLevel", str(dictionary_of_values.get("TopLevel")))
+ layer1d_root.set(
+ "IsAquifer", str(dictionary_of_values.get("IsAquifer")).lower()
+ )
+ layer1d_root.set(
+ "WaterpressureInterpolationModel",
+ str(dictionary_of_values.get("WaterpressureInterpolationModel").value),
+ )
+ return layer1d_root
+
+
+class SoilProfile1D(BaseDataClass):
+ """
+ Dataclass that contains a 1D soil profile
+
+ :param Name: name of the soil profile
+ :param BottomLevel: bottom level of the whole soil profile
+ :param Layers1D: list of layers included in the soil profile
+
+ """
+
+ Name: str
+ BottomLevel: float
+ Layers1D: List[Layer1D] = []
+
+ def serialize(self) -> et.Element:
+ """
+ Function that serializes the class SoilProfile1D class.
+ """
+ soilprofile1d_root = et.Element("SoilProfile1D")
+ dictionary_of_values = self.dict()
+ soilprofile1d_root.set("Name", dictionary_of_values.get("Name"))
+ soilprofile1d_root.set(
+ "BottomLevel", str(dictionary_of_values.get("BottomLevel"))
+ )
+ layers1d_root = et.Element("Layers1D")
+ for layer in self.Layers1D:
+ layers1d_root.append(layer.serialize())
+ soilprofile1d_root.append(layers1d_root)
+ return soilprofile1d_root
Index: DamClients/DamPythonInterface/trunk/doc/source/dev/input.rst
===================================================================
diff -u -r3489 -r3490
--- DamClients/DamPythonInterface/trunk/doc/source/dev/input.rst (.../input.rst) (revision 3489)
+++ DamClients/DamPythonInterface/trunk/doc/source/dev/input.rst (.../input.rst) (revision 3490)
@@ -35,4 +35,12 @@
.. automodule:: dampythoninterface.stability_parameters
:members:
+ :undoc-members:
+
+Soil profile 1D
+---------------
+
+
+.. automodule:: dampythoninterface.soilprofile1D
+ :members:
:undoc-members:
\ No newline at end of file