// Copyright (C) Stichting Deltares 2024. All rights reserved.
//
// This file is part of the Dam Engine.
//
// The Dam Engine 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.
using System;
using System.Collections.Generic;
using System.Linq;
using Deltares.DamEngine.Calculators.KernelWrappers.Common;
using Deltares.DamEngine.Calculators.Properties;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Geotechnics;
namespace Deltares.DamEngine.Calculators.PlLinesCreator;
///
/// Soil profile validator (for 1D and 2D soil profile) for the creation of the piezometric level lines.
///
public class SoilProfileValidator
{
private enum LayerType
{
Aquifer,
Aquitard
}
public SoilProfileType SoilProfileType { get; init; }
public SoilProfile1D SoilProfile1D { get; init; }
public SoilProfile2D SoilProfile2D { get; init; }
public Soil DikeEmbankmentMaterial { get; init; }
public SurfaceLine2 SurfaceLine { get; init; }
public void ValidateSoilProfileForPlLinesCreator()
{
ThrowIfInvalidSurfaceLine();
ThrowIfRequiredCharacteristicPointsAreMissing();
ThrowIfInsufficientSoilGeometryData();
ThrowsIfNoLayerWithType(LayerType.Aquifer);
ThrowsIfNoLayerWithType(LayerType.Aquitard);
ThrowIfNoContinuousBottomAquifer();
ThrowIfDiscontinuousInBetweenAquifer();
}
///
/// Check if the lowest layer is a continuous aquifer.
///
///
private void ThrowIfNoContinuousBottomAquifer()
{
bool isNoBottomAquifer;
if (SoilProfileType == SoilProfileType.ProfileType1D)
{
SoilProfile1D actualSoilProfile = DetermineSoilProfileAtDikeTopAtPolder();
SoilLayer1D relevantAquiferLayer = actualSoilProfile.BottomAquiferLayer;
isNoBottomAquifer = relevantAquiferLayer == null;
}
else
{
SoilProfile2DHelper.DetermineAquiferLayerBoundaryPoints(SoilProfile2DHelper.LayerType.BottomAquiferCluster, SoilProfile2D,
out Point2D[] _,
out Point2D[] bottomAquiferTopCoordinates);
isNoBottomAquifer = (bottomAquiferTopCoordinates == null);
}
if (isNoBottomAquifer)
{
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General
+ string.Format(Resources.SoilProfileValidator_NoContinuousBottomAquiferLayer, SoilProfile2D.Name));
}
}
///
/// Check if no isolated in-between aquifer(s) are present, which means that all the in-between aquifers must be continuous
/// aquifers from left to right of the geometry or of the surface line.
///
///
private void ThrowIfDiscontinuousInBetweenAquifer()
{
if (SoilProfileType != SoilProfileType.ProfileType2D)
{
return;
}
if (SoilProfile2DHelper.IsAtLeastOneIsolatedInBetweenAquiferPresent(SoilProfile2D))
{
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General
+ string.Format(Resources.SoilProfileValidator_DiscontinuousAquiferPresent, SoilProfile2D.Name));
}
}
///
/// Check if at least one layer with the given type is present in the soil profile.
///
/// The type of layer: aquifer or aquitard.
///
private void ThrowsIfNoLayerWithType(LayerType layerType)
{
bool isNoLayerWithGivenType;
if (SoilProfileType == SoilProfileType.ProfileType1D)
{
SoilProfile1D actualSoilProfile = DetermineSoilProfileAtDikeTopAtPolder();
IList aquiferLayers = actualSoilProfile.GetAquiferLayers();
isNoLayerWithGivenType = layerType == LayerType.Aquifer ? aquiferLayers.Count == 0 : actualSoilProfile.Layers.Count - aquiferLayers.Count == 0;
}
else
{
IList aquiferLayers = SoilProfile2D.Surfaces.Where(s => s.IsAquifer).ToList();
isNoLayerWithGivenType = layerType == LayerType.Aquifer ? aquiferLayers.Count == 0 : SoilProfile2D.Surfaces.Count - aquiferLayers.Count == 0;
}
if (isNoLayerWithGivenType)
{
string message = layerType == LayerType.Aquifer ? Resources.SoilProfileValidator_NoAquifer : Resources.SoilProfileValidator_NoAquitard;
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General + message);
}
}
///
/// Check if enough soil geometry data available.
///
private void ThrowIfInsufficientSoilGeometryData()
{
bool hasNoGeometry1DData = (SoilProfileType == SoilProfileType.ProfileType1D) && (SoilProfile1D == null || DikeEmbankmentMaterial == null);
bool hasNoGeometry2DData = (SoilProfileType == SoilProfileType.ProfileType2D) && (SoilProfile2D == null);
if (hasNoGeometry1DData || hasNoGeometry2DData)
{
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General
+ Resources.SoilProfileValidator_InsufficientSoilGeometryData);
}
}
///
/// Check if all the required characteristic points exist.
///
private void ThrowIfRequiredCharacteristicPointsAreMissing()
{
if (!SurfaceLine.HasAnnotation(CharacteristicPointType.DikeTopAtRiver) ||
!SurfaceLine.HasAnnotation(CharacteristicPointType.DikeTopAtPolder) ||
!SurfaceLine.HasAnnotation(CharacteristicPointType.DikeToeAtPolder))
{
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General
+ Resources.SoilProfileValidator_RequiredCharacteristicPointsMissing);
}
}
///
/// Check if a correct surface line has been imported.
///
private void ThrowIfInvalidSurfaceLine()
{
if (SurfaceLine == null)
{
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General
+ Resources.SoilProfileValidator_NoSurfaceLineDefined);
}
if (SurfaceLine.Geometry.Points.Count < 2)
{
throw new PlLinesCreatorException(Resources.SoilProfileValidator_General
+ Resources.SoilProfileValidator_AtLeastTwoSurfaceLinePoints);
}
}
private SoilProfile1D DetermineSoilProfileBelowPoint(double xCoordinate)
{
SoilProfile1D soilProfile1D;
switch (SoilProfileType)
{
case SoilProfileType.ProfileType1D:
soilProfile1D = SoilProfileHelper.DetermineForSurfaceLineCorrected1DProfileAtX(SoilProfile1D, SurfaceLine, xCoordinate, DikeEmbankmentMaterial);
return soilProfile1D;
case SoilProfileType.ProfileType2D:
soilProfile1D = SoilProfile2D.GetSoilProfile1D(xCoordinate);
return soilProfile1D;
default:
return null;
}
}
private SoilProfile1D DetermineSoilProfileAtDikeTopAtPolder()
{
Point2D relevantPoint = SurfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtPolder);
return DetermineSoilProfileBelowPoint(relevantPoint.X);
}
}