From cea29de96965422d3d7c6dbe5906fec720c8001c Mon Sep 17 00:00:00 2001 From: ftomei Date: Tue, 25 Feb 2025 16:57:20 +0100 Subject: [PATCH] add Soil Water Index --- agrolib/criteriaModel/criteria1DCase.cpp | 63 +++++++++++++++++++-- agrolib/criteriaModel/criteria1DCase.h | 1 + agrolib/criteriaModel/criteria1DProject.cpp | 24 +++++++- agrolib/criteriaModel/criteria1DProject.h | 1 + agrolib/gis/gis.cpp | 2 +- agrolib/mathFunctions/statistics.cpp | 4 +- agrolib/soil/soil.cpp | 2 +- bin/CRITERIA1D/main.cpp | 2 +- 8 files changed, 88 insertions(+), 11 deletions(-) diff --git a/agrolib/criteriaModel/criteria1DCase.cpp b/agrolib/criteriaModel/criteria1DCase.cpp index b9443082..96cf2808 100644 --- a/agrolib/criteriaModel/criteria1DCase.cpp +++ b/agrolib/criteriaModel/criteria1DCase.cpp @@ -724,7 +724,7 @@ double Crit1DCase::getDegreeOfSaturation(double computationDepth) lowerDepth = soilLayers[i].depth + soilLayers[i].thickness * 0.5; if (computationDepth >= upperDepth && computationDepth <= lowerDepth) { - return soilLayers[i].waterContent / soilLayers[i].SAT; + return soilLayers[i].getDegreeOfSaturation(); } } @@ -732,6 +732,53 @@ double Crit1DCase::getDegreeOfSaturation(double computationDepth) } +/*! + * \brief getSoilWaterIndex + * compute Soil Water Index (SWI) + * 0: wilting point + * 1: soil saturation + * \param computationDepth = computation soil depth [cm] + * \return soil water index [-] averaged from zero to specific depth + */ +double Crit1DCase::getSoilWaterIndex(double computationDepth) +{ + computationDepth /= 100; // [cm] --> [m] + if (computationDepth <= 0 || mySoil.totalDepth < (computationDepth * 0.25)) + { + return NODATA; + } + + double lowerDepth, upperDepth; // [m] + double depthFraction; // [-] + double currentWaterSum; // [mm] + double potentialWaterSum = 0; // [mm] + + currentWaterSum = soilLayers[0].waterContent; // pond [mm] + + bool islastComputationLayer = false; + unsigned int i = 1; + while (i < soilLayers.size() && ! islastComputationLayer) + { + upperDepth = soilLayers[i].depth - soilLayers[i].thickness * 0.5; + lowerDepth = soilLayers[i].depth + soilLayers[i].thickness * 0.5; + + if (lowerDepth < computationDepth) + depthFraction = 1; + else + { + depthFraction = (computationDepth - upperDepth) / soilLayers[i].thickness; + islastComputationLayer = true; + } + + currentWaterSum += (soilLayers[i].waterContent - soilLayers[i].WP) * depthFraction; + potentialWaterSum += (soilLayers[i].SAT - soilLayers[i].WP) * depthFraction; + i++; + } + + return currentWaterSum / potentialWaterSum; +} + + /*! * \brief getWaterPotential * \param computationDepth = computation soil depth [cm] @@ -799,27 +846,28 @@ double Crit1DCase::getSlopeStability(double computationDepth) /*! * \brief getWaterDeficit * \param computationDepth = computation soil depth [cm] - * \return sum of water deficit from zero to computationDepth (mm) + * \return sum of soil water deficit (mm) from zero to computationDepth */ double Crit1DCase::getWaterDeficitSum(double computationDepth) { - computationDepth /= 100; // [cm] --> [m] + computationDepth /= 100.; // [cm] --> [m] double lowerDepth, upperDepth; // [m] + double layerDeficit; // [mm] double waterDeficitSum = 0; // [mm] for (unsigned int i = 1; i < soilLayers.size(); i++) { lowerDepth = soilLayers[i].depth + soilLayers[i].thickness * 0.5; + layerDeficit = soilLayers[i].FC - soilLayers[i].waterContent; if (lowerDepth < computationDepth) { - waterDeficitSum += soilLayers[i].FC - soilLayers[i].waterContent; + waterDeficitSum += layerDeficit; } else { // fraction of last layer upperDepth = soilLayers[i].depth - soilLayers[i].thickness * 0.5; - double layerDeficit = soilLayers[i].FC - soilLayers[i].waterContent; double depthFraction = (computationDepth - upperDepth) / soilLayers[i].thickness; return waterDeficitSum + layerDeficit * depthFraction; } @@ -903,6 +951,11 @@ double Crit1DCase::getAvailableWaterSum(double computationDepth) double Crit1DCase::getFractionAW(double computationDepth) { computationDepth /= 100; // [cm] --> [m] + if (computationDepth <= 0 || mySoil.totalDepth < (computationDepth * 0.25)) + { + return NODATA; + } + double lowerDepth, upperDepth; // [m] double depthFraction; // [-] double availableWaterSum = 0; // [mm] diff --git a/agrolib/criteriaModel/criteria1DCase.h b/agrolib/criteriaModel/criteria1DCase.h index 3ac543ee..fcbfdc0b 100644 --- a/agrolib/criteriaModel/criteria1DCase.h +++ b/agrolib/criteriaModel/criteria1DCase.h @@ -88,6 +88,7 @@ double getWaterDeficitSum(double computationDepth); double getWaterCapacitySum(double computationDepth); double getAvailableWaterSum(double computationDepth); + double getSoilWaterIndex(double computationDepth); private: double minLayerThickness; // [m] diff --git a/agrolib/criteriaModel/criteria1DProject.cpp b/agrolib/criteriaModel/criteria1DProject.cpp index 1932a083..241ddd6a 100644 --- a/agrolib/criteriaModel/criteria1DProject.cpp +++ b/agrolib/criteriaModel/criteria1DProject.cpp @@ -75,6 +75,7 @@ void Crit1DProject::initialize() availableWaterDepth.clear(); fractionAvailableWaterDepth.clear(); factorOfSafetyDepth.clear(); + soilWaterIndexDepth.clear(); awcDepth.clear(); texturalClassList.resize(13); @@ -367,6 +368,13 @@ bool Crit1DProject::readSettings() return false; } + depthList = projectSettings->value("soilWaterIndex").toStringList(); + if (! setVariableDepth(depthList, soilWaterIndexDepth)) + { + projectError = "Wrong Soil Water Index depth in " + configFileName; + return false; + } + projectSettings->endGroup(); return true; @@ -1709,6 +1717,11 @@ bool Crit1DProject::createOutputTable(QString &myError) QString fieldName = "FoS_" + QString::number(factorOfSafetyDepth[i]); queryString += ", " + fieldName + " REAL"; } + for (unsigned int i = 0; i < soilWaterIndexDepth.size(); i++) + { + QString fieldName = "SWI_" + QString::number(soilWaterIndexDepth[i]); + queryString += ", " + fieldName + " REAL"; + } // close query queryString += ")"; @@ -1784,6 +1797,11 @@ void Crit1DProject::updateOutput(Crit3DDate myDate, bool isFirst) QString fieldName = "FoS_" + QString::number(factorOfSafetyDepth[i]); outputString += ", " + fieldName; } + for (unsigned int i = 0; i < soilWaterIndexDepth.size(); i++) + { + QString fieldName = "SWI_" + QString::number(soilWaterIndexDepth[i]); + outputString += ", " + fieldName; + } outputString += ") VALUES "; } @@ -1850,12 +1868,16 @@ void Crit1DProject::updateOutput(Crit3DDate myDate, bool isFirst) } for (unsigned int i = 0; i < fractionAvailableWaterDepth.size(); i++) { - outputString += "," + QString::number(myCase.getFractionAW(fractionAvailableWaterDepth[i]), 'g', 3); + outputString += "," + QString::number(myCase.getFractionAW(fractionAvailableWaterDepth[i]), 'g', 4); } for (unsigned int i = 0; i < factorOfSafetyDepth.size(); i++) { outputString += "," + QString::number(myCase.getSlopeStability(factorOfSafetyDepth[i]), 'g', 4); } + for (unsigned int i = 0; i < soilWaterIndexDepth.size(); i++) + { + outputString += "," + QString::number(myCase.getSoilWaterIndex(soilWaterIndexDepth[i]), 'g', 4); + } outputString += ")"; } diff --git a/agrolib/criteriaModel/criteria1DProject.h b/agrolib/criteriaModel/criteria1DProject.h index 708c8f63..01eaaf4f 100644 --- a/agrolib/criteriaModel/criteria1DProject.h +++ b/agrolib/criteriaModel/criteria1DProject.h @@ -103,6 +103,7 @@ std::vector availableWaterDepth; // [cm] std::vector fractionAvailableWaterDepth; // [cm] std::vector factorOfSafetyDepth; // [cm] + std::vector soilWaterIndexDepth; // [cm] // DATABASE QSqlDatabase dbForecast; diff --git a/agrolib/gis/gis.cpp b/agrolib/gis/gis.cpp index 28a47949..546042d4 100644 --- a/agrolib/gis/gis.cpp +++ b/agrolib/gis/gis.cpp @@ -2055,7 +2055,7 @@ namespace gis } // step 3: cleans the basin (removes points relating to other basins) - float threshold = basinRaster.header->cellSize * 5; + double threshold = basinRaster.header->cellSize * 3.; for (int row = 0; row < basinRaster.header->nrRows; row++) { for (int col = 0; col < basinRaster.header->nrCols; col++) diff --git a/agrolib/mathFunctions/statistics.cpp b/agrolib/mathFunctions/statistics.cpp index db950e13..d85f2b95 100644 --- a/agrolib/mathFunctions/statistics.cpp +++ b/agrolib/mathFunctions/statistics.cpp @@ -320,8 +320,8 @@ namespace statistics double weighedMeanMultifactor(meanType type, std::vector > weights, std::vector &data) { double mean = NODATA; - int nrData = data.size(); - int nrWeightFactors = weights.size(); + int nrData = int(data.size()); + int nrWeightFactors = int(weights.size()); std::vector compositeWeights(nrData,1); std::vector normalizationCoefficient(nrWeightFactors,0); diff --git a/agrolib/soil/soil.cpp b/agrolib/soil/soil.cpp index d9fb6e96..5ee9f967 100644 --- a/agrolib/soil/soil.cpp +++ b/agrolib/soil/soil.cpp @@ -575,7 +575,7 @@ namespace soil /*! * \brief Compute degree of saturation from volumetric water content - * \param theta [m^3 m-3] volumetric water content + * \param theta [m3 m-3] volumetric water content * \param horizon pointer to Crit3DHorizon class * \return [-] degree of saturation */ diff --git a/bin/CRITERIA1D/main.cpp b/bin/CRITERIA1D/main.cpp index 7973afd2..5e0e02e1 100644 --- a/bin/CRITERIA1D/main.cpp +++ b/bin/CRITERIA1D/main.cpp @@ -31,7 +31,7 @@ void usage() int main(int argc, char *argv[]) { QCoreApplication myApp(argc, argv); - std::cout << "CRITERIA-1D agro-hydrological model v1.8.6\n" << std::endl; + std::cout << "CRITERIA-1D agro-hydrological model v1.8.7\n" << std::endl; Crit1DProject myProject;