Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/d serie 2023 2 msl 2296 #143

Merged
11 changes: 8 additions & 3 deletions geolib/models/dsettlement/dsettlement_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ def set_model(
is_probabilistic: bool,
is_horizontal_displacements: bool,
is_secondary_swelling: bool,
is_waspan: bool,
):
"""
Sets the D-settlement Model. Initializes CalculationOptions and Model if the type is str
Expand All @@ -128,7 +127,6 @@ def set_model(
is_probabilistic (bool): true if probabilistic calculation should be made
is_horizontal_displacements (bool): true if horizontal displacements should be calculated
is_secondary_swelling (bool): true if secondary swelling is present
is_waspan (bool): true if waspan

Returns:
Model
Expand All @@ -154,7 +152,6 @@ def set_model(
model_options.is_probabilistic = is_probabilistic
model_options.is_horizontal_displacements = is_horizontal_displacements
model_options.is_secondary_swelling = is_secondary_swelling
model_options.is_waspan = is_waspan

return model_options

Expand Down Expand Up @@ -236,6 +233,14 @@ def stdv_boundaries(self):
def distribution_boundaries(self):
return self.datastructure.input_data.geometry_data.distribution_boundaries

@property
def fit_options(self):
return self.datastructure.input_data.fit_options

@property
def fit_calculation(self):
return self.datastructure.input_data.fit_calculation

def set_probabilistic_data(
self,
point_of_vertical: Point,
Expand Down
44 changes: 24 additions & 20 deletions geolib/models/dsettlement/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
DSerieMatrixStructure,
DSerieOldTableStructure,
DSeriesInlineMappedProperties,
DSeriesInlineReversedProperties,
DSeriesMatrixTreeStructureCollection,
DSeriesNoParseSubStructure,
DSeriesRepeatedGroupedProperties,
Expand Down Expand Up @@ -608,28 +609,28 @@ def add_load(
return None


class Dimension(Enum):
class Dimension(IntEnum):
ONE_D = 0
TWO_D = 1


class ConsolidationModel(Enum):
class ConsolidationModel(IntEnum):
DARCY = 0
TERZAGHI = 1


class SoilModel(Enum):
class SoilModel(IntEnum):
NEN_KOPPEJAN = 0
NEN_BJERRUM = 1
ISOTACHE = 2


class StrainType(Enum):
class StrainType(IntEnum):
LINEAR = 0
NATURAL = 1


class Model(DSeriesNoParseSubStructure):
class Model(DSeriesInlineReversedProperties):
dimension: Dimension = Dimension.TWO_D
consolidation_model: ConsolidationModel = ConsolidationModel.DARCY
soil_model: SoilModel = SoilModel.NEN_KOPPEJAN
Expand All @@ -639,7 +640,6 @@ class Model(DSeriesNoParseSubStructure):
is_probabilistic: Bool = Bool.FALSE
is_horizontal_displacements: Bool = Bool.FALSE
is_secondary_swelling: Bool = Bool.FALSE
is_waspan: Bool = Bool.FALSE


class PreconPressureWithinLayer(Enum):
Expand Down Expand Up @@ -758,6 +758,17 @@ class InternalProbabilisticCalculationType(IntEnum):
BandWidthAndProbabilityOfFailureMonteCarlo = 2


class FitOptions(DSeriesInlineMappedProperties):
fit_maximum_number_of_iterations: conint(ge=0, le=100) = 5
fit_required_iteration_accuracy: confloat(ge=0, le=1) = 0.0001
fit_required_correlation_coefficient: confloat(ge=0, le=1) = 0.99


class FitCalculation(DSeriesInlineMappedProperties):
is_fit_calculation: Bool = Bool.FALSE
fit_vertical_number: conint(ge=-1, le=1000) = 0


class ProbabilisticData(DSeriesInlineMappedProperties):
reliability_x_co__ordinate: float = 0
residual_settlement: confloat(ge=0, le=1000) = 1
Expand Down Expand Up @@ -815,7 +826,7 @@ class DSettlementInputStructure(DSeriesStructure):
geometry_data: GeometryData = GeometryData()
geometry_1d_data: Optional[str]
run_identification: str = 2 * "\n"
model: Union[Model, str] = Model()
model: Model = Model()
verticals: Union[Verticals, str] = Verticals()
water: Union[float, str] = 9.81
non__uniform_loads: Union[NonUniformLoads, str] = NonUniformLoads()
Expand Down Expand Up @@ -886,19 +897,8 @@ class DSettlementInputStructure(DSeriesStructure):
ProbDefLayerDist=0
"""
)
fit_options: str = cleandoc(
"""
Fit Maximum Number of Iterations=5
Fit Required Iteration Accuracy=0.0001000000
Fit Required Correlation Coefficient=0.990
"""
)
fit_calculation: str = cleandoc(
"""
Is Fit Calculation=0
Fit Vertical Number=-1
"""
)
fit_options: FitOptions = FitOptions()
fit_calculation: FitCalculation = FitCalculation()
fit: str = ZERO_ITEMS

# Custom validator
Expand Down Expand Up @@ -981,9 +981,11 @@ class ResidualSettlements(DSerieOldTableStructure):
# TODO LIst[Dict[str, float]] but can be empty which now gives a validation error
residualsettlements: List[Dict[str, float]]


class CalculationSettings(DSeriesStructure):
is_secondary_swelling_used: bool = False


class Results(DSeriesRepeatedGroupedProperties):
"""Representation of [results] group in sld file."""
calculation_settings: Optional[CalculationSettings]
Expand All @@ -994,12 +996,14 @@ class Results(DSeriesRepeatedGroupedProperties):
dissipation_in_layers: Optional[str]
reliability_calculation_results: Optional[str]


class DSettlementOutputStructure(DSeriesStructure):
"""Representation of complete .sld file, inherting
the structure of the .sli file as well."""
results: Results
input_data: DSettlementInputStructure


class DSettlementStructure(DSeriesStructure):
input_data: DSettlementInputStructure = DSettlementInputStructure()
output_data: Optional[Results] = None
20 changes: 15 additions & 5 deletions geolib/models/dsettlement/templates/input.sli.j2
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ D-Settlement={{ version.d__settlement }}

[MODEL]
{% if model is mapping -%}
{{ model.dimension.value }} : Dimension = {{ model.dimension.name }}
{{ model.consolidation_model.value }} : Calculation type = {{ model.consolidation_model.name }}
{{ model.soil_model.value }} : Model = {{ model.soil_model.name }}
{{ model.strain_type.value }} : Strain type = {{ model.strain_type.name }}
{{ model.dimension.value }} : Dimension = {{ {0: '1D', 1: '2D'}[model.dimension.value] }}
{{ model.consolidation_model.value }} : Calculation type = {{ {0 : 'Darcy', 1 : 'Terzaghi'}[model.consolidation_model.value] }}
{{ model.soil_model.value }} : Model = {{ {0: 'NEN - Koppejan', 1: 'NEN - Bjerrum', 2: 'Isotache'}[model.soil_model.value] }}
{{ model.strain_type.value }} : Strain type = {{ {0: 'Linear', 1: 'Natural'}[model.strain_type.value] }}
{{ model.is_vertical_drains.value }} : Vertical drains = {{ model.is_vertical_drains.name }}
{{ model.is_fit_for_settlement_plate.value }} : Fit for settlement plate = {{ model.is_fit_for_settlement_plate.name }}
{{ model.is_probabilistic.value }} : Probabilistic = {{ model.is_probabilistic.name }}
{{ model.is_horizontal_displacements.value }} : Horizontal displacements = {{ model.is_horizontal_displacements.name }}
{{ model.is_secondary_swelling.value }} : Secondary swelling = {{ model.is_secondary_swelling.name }}
{{ model.is_waspan.value }} : Waspan = {{ model.is_waspan.name }}
{% else -%}
{{ model }}
{% endif %}
Expand Down Expand Up @@ -356,10 +355,21 @@ Is Reliability Calculation={{probabilistic_data.is_reliability_calculation.value
{{ probabilistic_defaults }}
[END OF PROBABILISTIC DEFAULTS]
[FIT OPTIONS]
{% if fit_options is mapping -%}
Fit Maximum Number of Iterations={{fit_options.fit_maximum_number_of_iterations}}
Fit Required Iteration Accuracy={{fit_options.fit_required_iteration_accuracy}}
Fit Required Correlation Coefficient={{fit_options.fit_required_correlation_coefficient}}
{% else %}
{{ fit_options }}
{% endif %}
[END OF FIT OPTIONS]
[FIT CALCULATION]
{% if fit_calculation is mapping -%}
Is Fit Calculation={{fit_calculation.is_fit_calculation.value}}
Fit Vertical Number={{fit_calculation.fit_vertical_number}}
{% else %}
{{ fit_calculation }}
{% endif %}
[END OF FIT CALCULATION]
[FIT]
{{ fit }}
Expand Down
60 changes: 58 additions & 2 deletions tests/models/dsettlement/test_acceptance.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
import pathlib
import shutil
from datetime import timedelta
from pathlib import Path
from typing import List
Expand Down Expand Up @@ -426,7 +427,6 @@ def test_set_model(self):
is_probabilistic=False,
is_horizontal_displacements=False,
is_secondary_swelling=True, # TODO document this parameter
is_waspan=False, # TODO document this parameter
)

path = self.outputdir / "test_set_model.sli"
Expand Down Expand Up @@ -571,7 +571,7 @@ def test_other_load(self):
dm.serialize(path)

@pytest.mark.acceptance
@pytest.mark.xfail # Wrong soils for now
@pytest.mark.xfail # Wrong soils for now
@only_teamcity
def test_sorting_vertical_layer_boundaries(self):
"""
Expand Down Expand Up @@ -643,3 +643,59 @@ def test_sorting_vertical_layer_boundaries(self):
# Verify geometry is correct and we can parse output
dm.execute() # will raise on execution error
assert dm.datastructure

@pytest.mark.acceptance
def test_run_fit(self):
# 1. Set up test data
test_folder = TestUtils.get_local_test_data_dir("dsettlement")
test_file = pathlib.Path(os.path.join(test_folder, "BeforeFit.sli"))
output_test_folder = Path(TestUtils.get_output_test_data_dir("dsettlement/acceptancetest/"))
output_test_inputfile = output_test_folder / ("FitCalculation.sli")
source = pathlib.Path(os.path.join(test_folder, "FitMeasurement.txt"))
dest = pathlib.Path(os.path.join(output_test_folder, "FitMeasurement.txt"))
shutil.copyfile(source, dest)

dm = DSettlementModel()

# 2. Verify initial expectations
assert test_file.exists()

# 3. Parse test file
dm.parse(test_file)
fit_origin = list(dm.datastructure.input_data.fit.split("\n"))

# 4. Select fit model option
assert not dm.datastructure.input_data.model.is_fit_for_settlement_plate
dm.datastructure.input_data.model.is_fit_for_settlement_plate = Bool.TRUE

# 5. Select vertical and fit calculation
assert dm.fit_calculation.fit_vertical_number == 0
dm.fit_calculation.fit_vertical_number = 1
assert not dm.fit_calculation.is_fit_calculation
dm.fit_calculation.is_fit_calculation = Bool.TRUE

# 6. Select fit iteration options
assert dm.fit_options.fit_maximum_number_of_iterations == 5
dm.fit_options.fit_maximum_number_of_iterations = 2
assert dm.fit_options.fit_required_iteration_accuracy == 0.0001
dm.fit_options.fit_required_iteration_accuracy = 0.001
assert dm.fit_options.fit_required_correlation_coefficient == 0.99
dm.fit_options.fit_required_correlation_coefficient = 0.9

# 7. Serialize file
dm.serialize(output_test_inputfile)

# 8. Run fit calculation (includes parsing of output file)
result = dm.execute()

# 9. Check that a fit calculation was performed,
# by checking a few lines in the FIT block in the INPUT part of the output file
assert fit_origin[33].strip() == '50.000 = X co-ordinate'
assert fit_origin[56].strip() == '1 1.000 1.000 10.000 Factor 0: selected, current, previous, weight'
assert fit_origin[67].strip() == '0.000 = Coefficient of determination -'
assert fit_origin[68].strip() == '0.19 = Imperfection m'
fit = list(result.input.fit.split("\n"))
assert fit[33].strip() == '50.000 = X co-ordinate'
assert fit[56].strip() == '1 1.051 1.000 10.000 Factor 0: selected, current, previous, weight'
assert fit[67].strip() == '0.841 = Coefficient of determination -'
assert fit[68].strip() == '0.50 = Imperfection m'
Loading