diff --git a/agrolib/climate/climate.cpp b/agrolib/climate/climate.cpp index 137add53..5ac40436 100644 --- a/agrolib/climate/climate.cpp +++ b/agrolib/climate/climate.cpp @@ -1101,7 +1101,7 @@ float thomDailyMean(TObsDataH* hourlyValues, float minimumPercentage) if ( (float(nData) / 24 * 100) < minimumPercentage) thomDailyMean = NODATA; else - thomDailyMean = statistics::mean(thomValues, nData); + thomDailyMean = statistics::mean(thomValues); return thomDailyMean; @@ -3826,7 +3826,7 @@ bool parseXMLElaboration(Crit3DElabList *listXMLElab, Crit3DAnomalyList *listXML meteoVariable var = getKeyMeteoVarMeteoMap(MapMonthlyMeteoVarToString, variable.toStdString()); if (var != noMeteoVar) { - listXMLDrought->updateVariable(var, listXMLDrought->listVariable().size() - 1); //change var + listXMLDrought->updateVariable(var, int(listXMLDrought->listVariable().size()) - 1); //change var } } if (myTag == "EXPORT") diff --git a/agrolib/climate/climate.h b/agrolib/climate/climate.h index 3235fd04..8ab2d66a 100644 --- a/agrolib/climate/climate.h +++ b/agrolib/climate/climate.h @@ -165,7 +165,6 @@ void setMpValues(Crit3DMeteoPoint meteoPointGet, Crit3DMeteoPoint* meteoPointSet, QDate myDate, meteoVariable myVar, Crit3DMeteoSettings* meteoSettings); meteoComputation getMeteoCompFromString(std::map map, std::string value); - - //int getClimateIndexFromDate(QDate myDate, period periodType); + #endif // CLIMATE_H diff --git a/agrolib/commonChartElements/dialogChangeAxis.cpp b/agrolib/commonChartElements/dialogChangeAxis.cpp index 6fd91e0b..c14f64fe 100644 --- a/agrolib/commonChartElements/dialogChangeAxis.cpp +++ b/agrolib/commonChartElements/dialogChangeAxis.cpp @@ -1,18 +1,24 @@ #include "dialogChangeAxis.h" -DialogChangeAxis::DialogChangeAxis(bool isLeftAxis_) +DialogChangeAxis::DialogChangeAxis(int nrAxis, bool isDate_) { - isLeftAxis = isLeftAxis_; + isDateAxis = isDate_; + QString title; - if (isLeftAxis) + if (nrAxis == 0) + { + title = "Change X Axis"; + } + else if (nrAxis == 1) { title = "Change Left Axis"; } - else + else if (nrAxis == 2) { title = "Change Right Axis"; } this->setWindowTitle(title); + QVBoxLayout* mainLayout = new QVBoxLayout; this->resize(200, 100); @@ -20,17 +26,32 @@ DialogChangeAxis::DialogChangeAxis(bool isLeftAxis_) QHBoxLayout *layoutEdit = new QHBoxLayout; QLabel minValueLabel("Minimum value:"); - minValueLabel.setBuddy(&minVal); - minVal.setValidator(new QDoubleValidator(-999.0, 999.0, 3)); + layoutEdit->addWidget(&minValueLabel); + if (isDateAxis) + { + minValueLabel.setBuddy(&minDate); + layoutEdit->addWidget(&minDate); + } + else + { + minValueLabel.setBuddy(&minVal); + minVal.setValidator(new QDoubleValidator(-9999.0, 9999.0, 3)); + layoutEdit->addWidget(&minVal); + } QLabel maxValueLabel("Maximum value:"); - maxValueLabel.setBuddy(&maxVal); - maxVal.setValidator(new QDoubleValidator(-999.0, 999.0, 3)); - - layoutEdit->addWidget(&minValueLabel); - layoutEdit->addWidget(&minVal); layoutEdit->addWidget(&maxValueLabel); - layoutEdit->addWidget(&maxVal); + if (isDateAxis) + { + minValueLabel.setBuddy(&maxDate); + layoutEdit->addWidget(&maxDate); + } + else + { + maxValueLabel.setBuddy(&maxVal); + maxVal.setValidator(new QDoubleValidator(-9999.0, 9999.0, 3)); + layoutEdit->addWidget(&maxVal); + } QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -55,16 +76,28 @@ void DialogChangeAxis::done(bool res) { if (res) // ok { - if (minVal.text().isEmpty()) + if (isDateAxis) { - QMessageBox::information(nullptr, "Missing min value", "Insert min val"); - return; + if (minDate.date() >= maxDate.date()) + { + QMessageBox::warning(nullptr, "Wrong dates!", "Insert correct dates."); + return; + } } - if (maxVal.text().isEmpty()) + else { - QMessageBox::information(nullptr, "Missing max value", "Insert max val"); - return; + if (minVal.text().isEmpty()) + { + QMessageBox::warning(nullptr, "Missing min value", "Insert minimum value."); + return; + } + if (maxVal.text().isEmpty()) + { + QMessageBox::warning(nullptr, "Missing max value", "Insert maximum value."); + return; + } } + QDialog::done(QDialog::Accepted); return; } @@ -84,3 +117,13 @@ float DialogChangeAxis::getMaxVal() const { return maxVal.text().toFloat(); } + +QDate DialogChangeAxis::getMinDate() const +{ + return minDate.date(); +} + +QDate DialogChangeAxis::getMaxDate() const +{ + return maxDate.date(); +} diff --git a/agrolib/commonChartElements/dialogChangeAxis.h b/agrolib/commonChartElements/dialogChangeAxis.h index a6339371..bf230494 100644 --- a/agrolib/commonChartElements/dialogChangeAxis.h +++ b/agrolib/commonChartElements/dialogChangeAxis.h @@ -8,16 +8,24 @@ Q_OBJECT private: - bool isLeftAxis; + bool isDateAxis; + + QDateEdit minDate; QLineEdit minVal; + + QDateEdit maxDate; QLineEdit maxVal; public: - DialogChangeAxis(bool isLeftAxis); + DialogChangeAxis(int nrAxis, bool isDate_); ~DialogChangeAxis() override; void done(bool res); + float getMinVal() const; float getMaxVal() const; + + QDate getMinDate() const; + QDate getMaxDate() const; }; #endif // DIALOGCHANGEAXIS_H diff --git a/agrolib/crit3dDate/crit3dDate.cpp b/agrolib/crit3dDate/crit3dDate.cpp index dc112ca8..09b83f14 100644 --- a/agrolib/crit3dDate/crit3dDate.cpp +++ b/agrolib/crit3dDate/crit3dDate.cpp @@ -208,31 +208,10 @@ Crit3DDate min(const Crit3DDate& myDate1, const Crit3DDate& myDate2) Crit3DDate getDateFromDoy(int year, int doy) { - if (doy < 1) return NO_DATE; - short month; - - // before 29 february - if (doy <= 59) - { - month = (doy <= 31) ? 1 : 2; - return Crit3DDate(doy-doyMonth[month-1], month, year); - } - - const short leap = isLeapYear(year) ? 1 : 0; - if (doy > (365 + leap)) return NO_DATE; - - // 29 february - if (doy == 60 && leap == 1) - return Crit3DDate(29, 2, year); - - // after - month = 3; - while (month <= 12 && doy > (doyMonth[month]+leap)) - month++; - - return Crit3DDate(doy-(doyMonth[month-1]+leap), month, year); + return Crit3DDate(1, 1, year).addDays(doy-1); } + void Crit3DDate::setNullDate() { day = 0; diff --git a/agrolib/criteria1DWidget/criteria1DWidget.cpp b/agrolib/criteria1DWidget/criteria1DWidget.cpp index 627a0ae8..ce837a15 100644 --- a/agrolib/criteria1DWidget/criteria1DWidget.cpp +++ b/agrolib/criteria1DWidget/criteria1DWidget.cpp @@ -171,10 +171,15 @@ Criteria1DWidget::Criteria1DWidget() waterContentGroup->setFixedWidth(this->width() * widthRatio); carbonNitrogenGroup->setFixedWidth(this->width() * widthRatio); - infoCaseGroup->setTitle("Case"); - infoCropGroup->setTitle("Crop"); + QFont normalFont, boldFont; + boldFont.setBold(true); + normalFont.setBold(false); + + infoCaseGroup->setFont(boldFont); + infoCaseGroup->setTitle("Case study"); infoMeteoGroup->setTitle("Meteo"); infoSoilGroup->setTitle("Soil"); + infoCropGroup->setTitle("Crop"); laiParametersGroup->setTitle("Crop parameters"); rootParametersGroup->setTitle("Root parameters"); irrigationParametersGroup->setTitle("Irrigation parameters"); @@ -182,6 +187,7 @@ Criteria1DWidget::Criteria1DWidget() waterContentGroup->setTitle("Water Content variable"); carbonNitrogenGroup->setTitle("Carbon Nitrogen variable"); + caseListComboBox.setFont(normalFont); caseInfoLayout->addWidget(&caseListComboBox); cropInfoLayout->addWidget(cropId, 0, 0); @@ -435,9 +441,9 @@ Criteria1DWidget::Criteria1DWidget() carbonNitrogenGroup->setLayout(carbonNitrogenLayout); infoLayout->addWidget(infoCaseGroup); - infoLayout->addWidget(infoCropGroup); infoLayout->addWidget(infoMeteoGroup); infoLayout->addWidget(infoSoilGroup); + infoLayout->addWidget(infoCropGroup); infoLayout->addWidget(laiParametersGroup); infoLayout->addWidget(rootParametersGroup); infoLayout->addWidget(irrigationParametersGroup); @@ -594,6 +600,7 @@ void Criteria1DWidget::on_actionOpenProject() this->lastYearListComboBox.blockSignals(false); openComputationUnitsDB(myProject.dbComputationUnitsName); + viewMenu->setEnabled(true); if (soilListComboBox.count() == 0) { @@ -1053,15 +1060,20 @@ void Criteria1DWidget::on_actionChooseCase() // METEO meteoListComboBox.setCurrentText(myProject.myCase.unit.idMeteo); - // CROP + // CROP ID myProject.myCase.unit.idCrop = getIdCropFromClass(myProject.dbCrop, "crop_class", "id_class", myProject.myCase.unit.idCropClass, errorStr); - if (myProject.myCase.unit.idCrop != "") + if (myProject.myCase.unit.idCrop == "") + { + // it is a single crop, not a crop class + myProject.myCase.unit.idCrop = myProject.myCase.unit.idCropClass; + } + if ( cropListComboBox.findText(myProject.myCase.unit.idCrop) != -1 ) { cropListComboBox.setCurrentText(myProject.myCase.unit.idCrop); } else { - QMessageBox::critical(nullptr, "Error!", "Missing crop class: " + myProject.myCase.unit.idCropClass + "\n" + errorStr); + QMessageBox::critical(nullptr, "Error!", "Missing crop: " + myProject.myCase.unit.idCropClass + "\n" + errorStr); } // SOIL diff --git a/agrolib/criteria1DWidget/tabIrrigation.cpp b/agrolib/criteria1DWidget/tabIrrigation.cpp index eee9775b..8d64d5a3 100644 --- a/agrolib/criteria1DWidget/tabIrrigation.cpp +++ b/agrolib/criteria1DWidget/tabIrrigation.cpp @@ -15,24 +15,31 @@ TabIrrigation::TabIrrigation() seriesLAI = new QLineSeries(); seriesMaxTransp = new QLineSeries(); - seriesRealTransp = new QLineSeries(); - - seriesLAI->setName("LAI [m2 m-2]"); - seriesMaxTransp->setName("Transpiration max [mm]"); - seriesRealTransp->setName("Transpiration real [mm]"); - - seriesLAI->setColor(QColor(Qt::darkGreen)); - seriesMaxTransp->setColor(QColor(0,0,1,255)); - seriesRealTransp->setColor(QColor(Qt::red)); + seriesActualTransp = new QLineSeries(); + seriesMaxEvap = new QLineSeries(); + seriesActualEvap = new QLineSeries(); + + seriesLAI->setName("LAI [m2 m-2] "); + seriesMaxTransp->setName("max. Transpiration [mm]"); + seriesActualTransp->setName("actual Transpiration [mm]"); + seriesMaxEvap->setName("max. Evaporation [mm]"); + seriesActualEvap->setName("actual Evaporation [mm]"); + + QPen pen; + pen.setWidth(2); + pen.setColor(QColor(0, 200, 0, 255)); + seriesLAI->setPen(pen); + + // bug with black + seriesMaxTransp->setColor(QColor(0, 0, 1, 255)); + seriesActualTransp->setColor(QColor(Qt::red)); + seriesMaxEvap->setColor(QColor(Qt::gray)); + seriesActualEvap->setColor(QColor(210, 150, 20, 255)); seriesPrecIrr = new QBarSeries(); setPrec = new QBarSet("Precipitation [mm]"); setIrrigation = new QBarSet("Irrigation [mm]"); - setPrec->setColor(QColor(Qt::blue)); - setPrec->setBorderColor(QColor(Qt::blue)); - setIrrigation->setColor(QColor(Qt::cyan)); - setIrrigation->setBorderColor(QColor(Qt::cyan)); seriesPrecIrr->append(setPrec); seriesPrecIrr->append(setIrrigation); @@ -58,7 +65,7 @@ TabIrrigation::TabIrrigation() axisY->setRange(0,8); axisY->setTickCount(9); - axisYdx->setTitleText("Prec - Irrigation [mm]"); + axisYdx->setTitleText("Precipitation - Irrigation [mm]"); axisYdx->setTitleFont(font); axisYdx->setRange(0,40); axisYdx->setTickCount(9); @@ -70,17 +77,23 @@ TabIrrigation::TabIrrigation() chart->addSeries(seriesLAI); chart->addSeries(seriesMaxTransp); - chart->addSeries(seriesRealTransp); + chart->addSeries(seriesActualTransp); + chart->addSeries(seriesMaxEvap); + chart->addSeries(seriesActualEvap); chart->addSeries(seriesPrecIrr); seriesLAI->attachAxis(axisX); seriesMaxTransp->attachAxis(axisX); - seriesRealTransp->attachAxis(axisX); + seriesActualTransp->attachAxis(axisX); + seriesMaxEvap->attachAxis(axisX); + seriesActualEvap->attachAxis(axisX); seriesPrecIrr->attachAxis(axisX); seriesLAI->attachAxis(axisY); seriesMaxTransp->attachAxis(axisY); - seriesRealTransp->attachAxis(axisY); + seriesActualTransp->attachAxis(axisY); + seriesMaxEvap->attachAxis(axisY); + seriesActualEvap->attachAxis(axisY); seriesPrecIrr->attachAxis(axisYdx); chart->legend()->setVisible(true); @@ -96,8 +109,10 @@ TabIrrigation::TabIrrigation() m_tooltip->hide(); connect(seriesLAI, &QLineSeries::hovered, this, &TabIrrigation::tooltipLAI); - connect(seriesMaxTransp, &QLineSeries::hovered, this, &TabIrrigation::tooltipMT); - connect(seriesRealTransp, &QLineSeries::hovered, this, &TabIrrigation::tooltipRT); + connect(seriesMaxTransp, &QLineSeries::hovered, this, &TabIrrigation::tooltipEvapTransp); + connect(seriesActualTransp, &QLineSeries::hovered, this, &TabIrrigation::tooltipEvapTransp); + connect(seriesMaxEvap, &QLineSeries::hovered, this, &TabIrrigation::tooltipEvapTransp); + connect(seriesActualEvap, &QLineSeries::hovered, this, &TabIrrigation::tooltipEvapTransp); connect(seriesPrecIrr, &QHorizontalBarSeries::hovered, this, &TabIrrigation::tooltipPrecIrr); foreach(QLegendMarker* marker, chart->legend()->markers()) { @@ -138,7 +153,9 @@ void TabIrrigation::computeIrrigation(Crit1DCase &myCase, int firstYear, int las axisX->clear(); seriesLAI->clear(); seriesMaxTransp->clear(); - seriesRealTransp->clear(); + seriesActualTransp->clear(); + seriesMaxEvap->clear(); + seriesActualEvap->clear(); categories.clear(); if (setPrec!= nullptr) @@ -152,8 +169,8 @@ void TabIrrigation::computeIrrigation(Crit1DCase &myCase, int firstYear, int las { seriesPrecIrr->remove(setIrrigation); setIrrigation = new QBarSet("Irrigation [mm]"); - setIrrigation->setColor(QColor(Qt::cyan)); - setIrrigation->setBorderColor(QColor(Qt::cyan)); + setIrrigation->setColor(QColor(16,183,235,255)); + setIrrigation->setBorderColor(QColor(16,183,235,255)); } int currentDoy = 1; @@ -183,7 +200,9 @@ void TabIrrigation::computeIrrigation(Crit1DCase &myCase, int firstYear, int las categories.append(QString::number(doy)); seriesLAI->append(doy, myCase.crop.LAI); seriesMaxTransp->append(doy, myCase.output.dailyMaxTranspiration); - seriesRealTransp->append(doy, myCase.output.dailyTranspiration); + seriesActualTransp->append(doy, myCase.output.dailyTranspiration); + seriesMaxEvap->append(doy, myCase.output.dailyMaxEvaporation); + seriesActualEvap->append(doy, myCase.output.dailyEvaporation); *setPrec << myCase.output.dailyPrec; *setIrrigation << myCase.output.dailyIrrigation; } @@ -215,14 +234,14 @@ void TabIrrigation::computeIrrigation(Crit1DCase &myCase, int firstYear, int las } } -void TabIrrigation::tooltipLAI(QPointF point, bool state) +void TabIrrigation::tooltipLAI(QPointF point, bool isShow) { - if (state) + if (isShow) { QDate xDate(firstYear, 1, 1); int doy = int(round(point.x())); // start from 0 xDate = xDate.addDays(doy); - m_tooltip->setText(QString("%1 \nLAI %2 ").arg(xDate.toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); + m_tooltip->setText(QString("%1\nLAI: %2 [m2 m-2]").arg(xDate.toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); m_tooltip->setAnchor(point); m_tooltip->setZValue(11); m_tooltip->updateGeometry(); @@ -234,14 +253,14 @@ void TabIrrigation::tooltipLAI(QPointF point, bool state) } } -void TabIrrigation::tooltipMT(QPointF point, bool state) +void TabIrrigation::tooltipEvapTransp(QPointF point, bool isShow) { - if (state) + if (isShow) { QDate xDate(firstYear, 1, 1); int doy = int(round(point.x())); xDate = xDate.addDays(doy); - m_tooltip->setText(QString("%1 \nTransp max %2 ").arg(xDate.toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); + m_tooltip->setText(xDate.toString("yyyy-MM-dd") + "\n" + QString::number(point.y(),'f', 2)+ " mm"); m_tooltip->setAnchor(point); m_tooltip->setZValue(11); m_tooltip->updateGeometry(); @@ -251,34 +270,14 @@ void TabIrrigation::tooltipMT(QPointF point, bool state) { m_tooltip->hide(); } - } -void TabIrrigation::tooltipRT(QPointF point, bool state) -{ - if (state) - { - QDate xDate(firstYear, 1, 1); - int doy = int(round(point.x())); - xDate = xDate.addDays(doy); - m_tooltip->setText(QString("%1 \nTransp real %2 ").arg(xDate.toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); - m_tooltip->setAnchor(point); - m_tooltip->setZValue(11); - m_tooltip->updateGeometry(); - m_tooltip->show(); - } - else - { - m_tooltip->hide(); - } -} -void TabIrrigation::tooltipPrecIrr(bool state, int index, QBarSet *barset) -{ - if (state && barset!=nullptr && index < barset->count()) +void TabIrrigation::tooltipPrecIrr(bool isShow, int index, QBarSet *barset) +{ + if (isShow && barset!=nullptr && index < barset->count()) { - QPoint point = QCursor::pos(); QPoint mapPoint = chartView->mapFromGlobal(point); QPointF pointF = chart->mapToValue(mapPoint,seriesPrecIrr); @@ -291,11 +290,11 @@ void TabIrrigation::tooltipPrecIrr(bool state, int index, QBarSet *barset) QString valueStr; if (barset->label() == "Precipitation [mm]") { - valueStr = QString("%1 \nPrecipitation [mm] %2 ").arg(xDate.toString("yyyy-MM-dd")).arg(barset->at(index), 0, 'f', 1); + valueStr = QString("%1\nPrecipitation: %2 mm").arg(xDate.toString("yyyy-MM-dd")).arg(barset->at(index), 0, 'f', 1); } else if (barset->label() == "Irrigation [mm]") { - valueStr = QString("%1 \nIrrigation [mm] %2 ").arg(xDate.toString("yyyy-MM-dd")).arg(barset->at(index), 0, 'f', 1); + valueStr = QString("%1\nIrrigation: %2 mm").arg(xDate.toString("yyyy-MM-dd")).arg(barset->at(index), 0, 'f', 1); } m_tooltip->setText(valueStr); diff --git a/agrolib/criteria1DWidget/tabIrrigation.h b/agrolib/criteria1DWidget/tabIrrigation.h index 139ecdbc..2d5aedc7 100644 --- a/agrolib/criteria1DWidget/tabIrrigation.h +++ b/agrolib/criteria1DWidget/tabIrrigation.h @@ -15,10 +15,10 @@ TabIrrigation(); void computeIrrigation(Crit1DCase &myCase, int firstYear, int lastYear, const QDate &lastDBMeteoDate); - void tooltipLAI(QPointF point, bool state); - void tooltipMT(QPointF point, bool state); - void tooltipRT(QPointF point, bool state); - void tooltipPrecIrr(bool state, int index, QBarSet *barset); + void tooltipLAI(QPointF point, bool isShow); + void tooltipEvapTransp(QPointF point, bool isShow); + void tooltipPrecIrr(bool isShow, int index, QBarSet *barset); + void handleMarkerClicked(); private: @@ -32,7 +32,9 @@ QList categories; QLineSeries* seriesLAI; QLineSeries* seriesMaxTransp; - QLineSeries* seriesRealTransp; + QLineSeries* seriesActualTransp; + QLineSeries* seriesMaxEvap; + QLineSeries* seriesActualEvap; QBarSeries* seriesPrecIrr; QBarSet *setPrec; QBarSet *setIrrigation; diff --git a/agrolib/criteria1DWidget/tabLAI.cpp b/agrolib/criteria1DWidget/tabLAI.cpp index 4f033b3f..3fe8ae30 100644 --- a/agrolib/criteria1DWidget/tabLAI.cpp +++ b/agrolib/criteria1DWidget/tabLAI.cpp @@ -18,25 +18,35 @@ TabLAI::TabLAI() chartView->setChart(chart); seriesLAI = new QLineSeries(); - seriesPotentialEvap = new QLineSeries(); - seriesMaxEvap = new QLineSeries(); + seriesETP = new QLineSeries(); seriesMaxTransp = new QLineSeries(); - seriesLAI->setName("Leaf Area Index [m2 m-2]"); - seriesPotentialEvap->setName("Potential evapotranspiration [mm]"); - seriesPotentialEvap->setColor(QColor(Qt::darkGray)); - seriesMaxEvap->setName("Evaporation max [mm]"); - seriesMaxEvap->setColor(QColor(Qt::blue)); - seriesMaxTransp->setName("Transpiration max [mm]"); + seriesMaxEvap = new QLineSeries(); + + seriesLAI->setName("Leaf Area Index [m2 m-2] "); + seriesETP->setName("Potential evapotranspiration [mm] "); + seriesMaxTransp->setName("Maximum transpiration [mm] "); + seriesMaxEvap->setName("Maximum evaporation [mm] "); + + QPen pen; + pen.setWidth(2); + seriesLAI->setPen(pen); + + seriesLAI->setColor(QColor(0, 200, 0, 255)); seriesMaxTransp->setColor(QColor(Qt::red)); + seriesMaxEvap->setColor(QColor(Qt::blue)); + + // bug with black + seriesETP->setColor(QColor(0, 0, 16, 255)); axisX = new QDateTimeAxis(); axisY = new QValueAxis(); axisYdx = new QValueAxis(); chart->addSeries(seriesLAI); - chart->addSeries(seriesPotentialEvap); - chart->addSeries(seriesMaxEvap); + chart->addSeries(seriesETP); chart->addSeries(seriesMaxTransp); + chart->addSeries(seriesMaxEvap); + QDate first(QDate::currentDate().year(), 1, 1); QDate last(QDate::currentDate().year(), 12, 31); axisX->setTitleText("Date"); @@ -46,32 +56,27 @@ TabLAI::TabLAI() axisX->setTickCount(13); chart->addAxis(axisX, Qt::AlignBottom); seriesLAI->attachAxis(axisX); - seriesPotentialEvap->attachAxis(axisX); + seriesETP->attachAxis(axisX); seriesMaxEvap->attachAxis(axisX); seriesMaxTransp->attachAxis(axisX); QFont font = axisX->titleFont(); + qreal maximum = 8; axisY->setTitleText("Leaf Area Index [m2 m-2]"); axisY->setTitleFont(font); - axisY->setRange(0,7); - axisY->setTickCount(8); - - QPen pen; - pen.setWidth(3); - pen.setBrush(Qt::green); + axisY->setRange(0, maximum); + axisY->setTickCount(maximum+1); axisYdx->setTitleText("Evapotranspiration [mm]"); - axisYdx->setRange(0,7); - axisYdx->setTickCount(8); axisYdx->setTitleFont(font); - - seriesLAI->setPen(pen); + axisYdx->setRange(0, maximum); + axisYdx->setTickCount(maximum+1); chart->addAxis(axisY, Qt::AlignLeft); chart->addAxis(axisYdx, Qt::AlignRight); seriesLAI->attachAxis(axisY); - seriesPotentialEvap->attachAxis(axisYdx); + seriesETP->attachAxis(axisYdx); seriesMaxEvap->attachAxis(axisYdx); seriesMaxTransp->attachAxis(axisYdx); @@ -87,9 +92,9 @@ TabLAI::TabLAI() m_tooltip->hide(); connect(seriesLAI, &QLineSeries::hovered, this, &TabLAI::tooltipLAI); - connect(seriesPotentialEvap, &QLineSeries::hovered, this, &TabLAI::tooltipPE); + connect(seriesETP, &QLineSeries::hovered, this, &TabLAI::tooltipPE); connect(seriesMaxEvap, &QLineSeries::hovered, this, &TabLAI::tooltipME); - connect(seriesMaxTransp, &QLineSeries::hovered, this, &TabLAI::tooltipMT); + connect(seriesMaxTransp, &QLineSeries::hovered, this, &TabLAI::tooltipMaxTranspiration); foreach(QLegendMarker* marker, chart->legend()->markers()) { @@ -129,12 +134,12 @@ void TabLAI::computeLAI(Crit3DCrop* myCrop, Crit3DMeteoPoint *meteoPoint, int fi std::string errorStr; chart->removeSeries(seriesLAI); - chart->removeSeries(seriesPotentialEvap); + chart->removeSeries(seriesETP); chart->removeSeries(seriesMaxEvap); chart->removeSeries(seriesMaxTransp); seriesLAI->clear(); - seriesPotentialEvap->clear(); + seriesETP->clear(); seriesMaxEvap->clear(); seriesMaxTransp->clear(); @@ -161,7 +166,7 @@ void TabLAI::computeLAI(Crit3DCrop* myCrop, Crit3DMeteoPoint *meteoPoint, int fi // ET0 dailyEt0 = ET0_Hargreaves(TRANSMISSIVITY_SAMANI_COEFF_DEFAULT, meteoPoint->latitude, doy, tmax, tmin); - seriesPotentialEvap->append(x.toMSecsSinceEpoch(), dailyEt0); + seriesETP->append(x.toMSecsSinceEpoch(), dailyEt0); seriesMaxEvap->append(x.toMSecsSinceEpoch(), myCrop->getMaxEvaporation(dailyEt0)); seriesMaxTransp->append(x.toMSecsSinceEpoch(), myCrop->getMaxTranspiration(dailyEt0)); seriesLAI->append(x.toMSecsSinceEpoch(), myCrop->LAI); @@ -175,12 +180,12 @@ void TabLAI::computeLAI(Crit3DCrop* myCrop, Crit3DMeteoPoint *meteoPoint, int fi axisX->setMax(QDateTime(last, QTime(0,0,0))); chart->addSeries(seriesLAI); - chart->addSeries(seriesPotentialEvap); + chart->addSeries(seriesETP); chart->addSeries(seriesMaxEvap); chart->addSeries(seriesMaxTransp); seriesLAI->attachAxis(axisY); - seriesPotentialEvap->attachAxis(axisYdx); + seriesETP->attachAxis(axisYdx); seriesMaxEvap->attachAxis(axisYdx); seriesMaxTransp->attachAxis(axisYdx); @@ -197,7 +202,7 @@ void TabLAI::tooltipLAI(QPointF point, bool state) { QDateTime xDate; xDate.setMSecsSinceEpoch(point.x()); - m_tooltip->setText(QString("%1 \nLAI: %2 ").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); + m_tooltip->setText(QString("%1\nLAI: %2 [m2 m-2]").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); m_tooltip->setAnchor(point); m_tooltip->setZValue(11); m_tooltip->updateGeometry(); @@ -213,7 +218,7 @@ void TabLAI::tooltipPE(QPointF point, bool state) { QDateTime xDate; xDate.setMSecsSinceEpoch(point.x()); - m_tooltip->setText(QString("%1 \nPot. ET: %2 ").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); + m_tooltip->setText(QString("%1\nETP: %2 mm").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); m_tooltip->setAnchor(point); m_tooltip->setZValue(11); m_tooltip->updateGeometry(); @@ -229,7 +234,7 @@ void TabLAI::tooltipME(QPointF point, bool state) { QDateTime xDate; xDate.setMSecsSinceEpoch(point.x()); - m_tooltip->setText(QString("%1 \nEvap. max: %2 ").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); + m_tooltip->setText(QString("%1\nmax. Evaporation: %2 mm").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); m_tooltip->setAnchor(point); m_tooltip->setZValue(11); m_tooltip->updateGeometry(); @@ -239,14 +244,14 @@ void TabLAI::tooltipME(QPointF point, bool state) } } -void TabLAI::tooltipMT(QPointF point, bool state) +void TabLAI::tooltipMaxTranspiration(QPointF point, bool state) { if (state) { QDateTime xDate; xDate.setMSecsSinceEpoch(point.x()); - m_tooltip->setText(QString("%1 \nTransp. max: %2 ").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); + m_tooltip->setText(QString("%1\nmax. Transpiration: %2 mm").arg(xDate.date().toString("yyyy-MM-dd")).arg(point.y(), 0, 'f', 1)); m_tooltip->setAnchor(point); m_tooltip->setZValue(11); m_tooltip->updateGeometry(); diff --git a/agrolib/criteria1DWidget/tabLAI.h b/agrolib/criteria1DWidget/tabLAI.h index 219a3264..af360bc3 100644 --- a/agrolib/criteria1DWidget/tabLAI.h +++ b/agrolib/criteria1DWidget/tabLAI.h @@ -20,13 +20,13 @@ void tooltipLAI(QPointF point, bool state); void tooltipPE(QPointF point, bool state); void tooltipME(QPointF point, bool state); - void tooltipMT(QPointF point, bool state); + void tooltipMaxTranspiration(QPointF point, bool state); void handleMarkerClicked(); private: QChartView *chartView; QChart *chart; QLineSeries *seriesLAI; - QLineSeries *seriesPotentialEvap; + QLineSeries *seriesETP; QLineSeries *seriesMaxEvap; QLineSeries *seriesMaxTransp; QDateTimeAxis *axisX; diff --git a/agrolib/criteriaModel/carbonNitrogenModel.cpp b/agrolib/criteriaModel/carbonNitrogenModel.cpp index ba00e09d..cba020b7 100644 --- a/agrolib/criteriaModel/carbonNitrogenModel.cpp +++ b/agrolib/criteriaModel/carbonNitrogenModel.cpp @@ -1840,8 +1840,10 @@ void Crit1DCarbonNitrogenProfile::N_harvest(Crit1DCase &myCase) // public functi // N of leaves is incorporated in litter through the upeer layer with a smoothly rate during the leaf fall double N_toLitter = 0; - // !!! verificare USR PSR - if (myCase.crop.roots.firstRootLayer == 0 && myCase.crop.roots.lastRootLayer == 0) + + if ((myCase.crop.roots.firstRootLayer == 0 && myCase.crop.roots.lastRootLayer == 0) + || myCase.crop.roots.firstRootLayer == NODATA || myCase.crop.roots.lastRootLayer == NODATA + || myCase.crop.isBareSoil() ) return; for (int l = myCase.crop.roots.firstRootLayer; l <= myCase.crop.roots.lastRootLayer; l++) // verificare i cicli for per cambio indici diff --git a/agrolib/criteriaModel/criteria1DCase.cpp b/agrolib/criteriaModel/criteria1DCase.cpp index cd529c15..f3e2f949 100644 --- a/agrolib/criteriaModel/criteria1DCase.cpp +++ b/agrolib/criteriaModel/criteria1DCase.cpp @@ -182,7 +182,7 @@ bool Crit1DCase::initializeNumericalFluxes(std::string &error) double maxSurfaceWater = crop.getSurfaceWaterPonding() * 0.001; // [m] double roughnessManning = 0.024; // [s m^-0.33] int surfaceIndex = 0; - soilFluxes3D::setSurfaceProperties(surfaceIndex, roughnessManning, maxSurfaceWater); + soilFluxes3D::setSurfaceProperties(surfaceIndex, roughnessManning); // center float x0 = 0; @@ -194,6 +194,7 @@ bool Crit1DCase::initializeNumericalFluxes(std::string &error) int nodeIndex = 0; soilFluxes3D::setNode(nodeIndex, x0, y0, z0, area, isSurface, true, BOUNDARY_RUNOFF, float(unit.slope), float(ly)); soilFluxes3D::setNodeSurface(nodeIndex, surfaceIndex); + soilFluxes3D::setNodePond(nodeIndex, maxSurfaceWater); soilFluxes3D::setNodeLink(nodeIndex, nodeIndex + 1, DOWN, float(area)); // set soil nodes @@ -298,15 +299,16 @@ bool Crit1DCase::computeNumericalFluxes(const Crit3DDate &myDate, std::string &e soilFluxes3D::initializeBalance(); // precipitation - // TODO improve for lat < 0 - int duration = 24; // [hours] winter - if (myDate.month >= 5 && myDate.month <= 9) + int precDuration = 24; // [hours] winter + if ( (meteoPoint.latitude > 0 && (myDate.month >= 5 && myDate.month <= 9)) + || (meteoPoint.latitude <= 0 && (myDate.month <= 3 || myDate.month >= 11)) ) { - duration = 12; // [hours] summer + precDuration = 12; // [hours] summer } - int precH0 = 13 - duration/2; - int precH1 = precH0 + duration -1; - double precFlux = (area * output.dailyPrec * 0.001) / (HOUR_SECONDS * duration); // [m3 s-1] + + int precH0 = 13 - precDuration/2; + int precH1 = precH0 + precDuration - 1; + double precFlux = (area * output.dailyPrec * 0.001) / (HOUR_SECONDS * precDuration); // [m3 s-1] // irrigation int irrH0 = 0; @@ -314,10 +316,17 @@ bool Crit1DCase::computeNumericalFluxes(const Crit3DDate &myDate, std::string &e double irrFlux = 0; if (! unit.isOptimalIrrigation && output.dailyIrrigation > 0) { - duration = int(output.dailyIrrigation / 3); // [hours] irrH0 = 6; // morning - irrH1 = irrH0 + duration -1; - irrFlux = (area * output.dailyIrrigation * 0.001) / (HOUR_SECONDS * duration); // [m3 s-1] + int maxDuration = 24 - irrH0 + 1; // [hours] + float mmHour = 3; + if (output.dailyIrrigation >= 10) + { + mmHour = 10; + } + int irrDuration = std::min(int(output.dailyIrrigation / mmHour), maxDuration); + + irrH1 = irrH0 + irrDuration - 1; + irrFlux = (area * output.dailyIrrigation * 0.001) / (HOUR_SECONDS * irrDuration); // [m3 s-1] } // daily cycle diff --git a/agrolib/criteriaModel/criteria1DMeteo.cpp b/agrolib/criteriaModel/criteria1DMeteo.cpp index f79b3b03..449c2859 100644 --- a/agrolib/criteriaModel/criteria1DMeteo.cpp +++ b/agrolib/criteriaModel/criteria1DMeteo.cpp @@ -714,8 +714,6 @@ bool fillDailyTempPrecCriteria1D(QSqlDatabase* dbMeteo, QString table, Crit3DMet } QDate date; - QDate previousDate(validYear-1, 12, 31); - QDate lastDate(validYear, 12, 31); float tmin = NODATA; float tmax = NODATA; float tavg = NODATA; @@ -728,6 +726,9 @@ bool fillDailyTempPrecCriteria1D(QSqlDatabase* dbMeteo, QString table, Crit3DMet const float tmax_min = -40; const float tmax_max = 60; + QList fieldList = getFieldsUpperCase(query); + bool existWatertable = fieldList.contains("WATERTABLE"); + do { getValue(query.value("date"), &date); @@ -736,8 +737,18 @@ bool fillDailyTempPrecCriteria1D(QSqlDatabase* dbMeteo, QString table, Crit3DMet getValue(query.value("prec"), &prec); // Watertable depth [m] - getValue(query.value("watertable"), &waterTable); - if (waterTable < 0.f) waterTable = NODATA; + if (existWatertable) + { + getValue(query.value("watertable"), &waterTable); + if (waterTable < 0.f) + { + waterTable = NODATA; + } + } + else + { + waterTable = NODATA; + } if (tmin < tmin_min || tmin > tmin_max) { diff --git a/agrolib/criteriaModel/criteria1DProject.cpp b/agrolib/criteriaModel/criteria1DProject.cpp index 68c6de56..a3e074d4 100644 --- a/agrolib/criteriaModel/criteria1DProject.cpp +++ b/agrolib/criteriaModel/criteria1DProject.cpp @@ -1095,7 +1095,11 @@ int Crit1DProject::computeAllUnits() } } - int infoStep = std::max(1, int(compUnitList.size() / 20)); + int infoStep = int(compUnitList.size()); + if (compUnitList.size() >= 20) + { + infoStep = int(compUnitList.size() / 20); + } logger.writeInfo("COMPUTE..."); try @@ -1108,25 +1112,20 @@ int Crit1DProject::computeAllUnits() logger.writeInfo(compUnitList[i].idCase + " - numerical computation..."); } - // CROP + // check if it is crop class compUnitList[i].idCrop = getIdCropFromClass(dbCrop, "crop_class", "id_class", compUnitList[i].idCropClass, projectError); if (compUnitList[i].idCrop == "") { - logger.writeInfo("Unit " + compUnitList[i].idCase + " " + compUnitList[i].idCropClass + " ***** missing CROP *****"); - isErrorCrop = true; - continue; + compUnitList[i].idCrop = compUnitList[i].idCropClass; } // IRRI_RATIO float irriRatio = getIrriRatioFromCropClass(dbCrop, "crop_class", "id_class", compUnitList[i].idCropClass, projectError); - - if ((isYearlyStatistics || isMonthlyStatistics || isSeasonalForecast || isEnsembleForecast || isShortTermForecast) - && (int(irriRatio) == int(NODATA))) + if (isEqual(irriRatio, NODATA)) { - logger.writeInfo("Unit " + compUnitList[i].idCase + " " + compUnitList[i].idCropClass + " ***** missing IRRIGATION RATIO *****"); - continue; + irriRatio = 1; } // SOIL @@ -1171,7 +1170,7 @@ int Crit1DProject::computeAllUnits() } } - if ((i+1) % infoStep == 0 && nrUnitsComputed > 0) + if ((i+1) % infoStep == 0 && nrUnitsComputed > 20) { double percentage = (i+1) * 100.0 / compUnitList.size(); logger.writeInfo("..." + QString::number(round(percentage)) + "%"); diff --git a/agrolib/criteriaModel/water1D.cpp b/agrolib/criteriaModel/water1D.cpp index 8dd4c0f1..e6d20bc7 100644 --- a/agrolib/criteriaModel/water1D.cpp +++ b/agrolib/criteriaModel/water1D.cpp @@ -373,8 +373,6 @@ double computeCapillaryRise(std::vector &soilLayers, double w double computeEvaporation(std::vector &soilLayers, double maxEvaporation) { - // TODO extend to geometric soilLayers - // surface evaporation double surfaceEvaporation = MINVALUE(maxEvaporation, soilLayers[0].waterContent); soilLayers[0].waterContent -= surfaceEvaporation; @@ -390,32 +388,43 @@ double computeEvaporation(std::vector &soilLayers, double max // soil evaporation int nrEvapLayers = int(floor(MAX_EVAPORATION_DEPTH / soilLayers[1].thickness)) +1; nrEvapLayers = std::min(nrEvapLayers, int(soilLayers.size()-1)); - double* coeffEvap = new double[nrEvapLayers]; - double layerDepth, coeffDepth; - double sumCoeff = 0; + std::vector coeffEvap; + coeffEvap.resize(nrEvapLayers); + double minDepth = soilLayers[1].depth + soilLayers[1].thickness / 2; + double sumCoeff = 0; for (int i=1; i <= nrEvapLayers; i++) { - layerDepth = soilLayers[i].depth + soilLayers[i].thickness / 2.0; + double layerDepth = soilLayers[i].depth + soilLayers[i].thickness / 2.0; - coeffDepth = MAXVALUE((layerDepth - minDepth) / (MAX_EVAPORATION_DEPTH - minDepth), 0); - // evaporation coefficient: 1 at depthMin, ~0.1 at MAX_EVAPORATION_DEPTH + double coeffDepth = MAXVALUE((layerDepth - minDepth) / (MAX_EVAPORATION_DEPTH - minDepth), 0); + // evaporation coefficient: 1 at depthMin, ~0.1 at maximum depth for evaporation coeffEvap[i-1] = exp(-2 * coeffDepth); sumCoeff += coeffEvap[i-1]; } + // normalize + std::vector coeffThreshold; + coeffThreshold.resize(nrEvapLayers); + for (int i=0; i < nrEvapLayers; i++) + { + coeffThreshold[i] = (1.0 - coeffEvap[i]) * 0.5; + coeffEvap[i] /= sumCoeff; + } + bool isWaterSupply = true; double sumEvap, evapLayerThreshold, evapLayer; - while ((residualEvaporation > EPSILON) && (isWaterSupply == true)) + int nrIteration = 0; + while ((residualEvaporation > EPSILON) && (isWaterSupply == true) && nrIteration < 3) { sumEvap = 0.0; for (int i=1; i <= nrEvapLayers; i++) { - evapLayer = residualEvaporation * (coeffEvap[i-1] / sumCoeff); - evapLayerThreshold = soilLayers[i].HH + (1 - coeffEvap[i-1]) * (soilLayers[i].FC - soilLayers[i].HH); + evapLayer = residualEvaporation * coeffEvap[i-1]; + evapLayerThreshold = soilLayers[i].HH + (soilLayers[i].FC - soilLayers[i].HH) * coeffThreshold[i-1]; if (soilLayers[i].waterContent > (evapLayerThreshold + evapLayer)) { @@ -441,10 +450,9 @@ double computeEvaporation(std::vector &soilLayers, double max residualEvaporation -= sumEvap; actualEvaporation += sumEvap; + nrIteration++; } - delete[] coeffEvap; - return actualEvaporation; } diff --git a/agrolib/criteriaModel/water1D.h b/agrolib/criteriaModel/water1D.h index af41c5c0..074e70fb 100644 --- a/agrolib/criteriaModel/water1D.h +++ b/agrolib/criteriaModel/water1D.h @@ -7,8 +7,6 @@ #include "soil.h" #endif - #define MAX_EVAPORATION_DEPTH 0.2 - class Crit3DCrop; void initializeWater(std::vector &soilLayers); diff --git a/agrolib/crop/crop.cpp b/agrolib/crop/crop.cpp index ba743041..5bdd9fb4 100644 --- a/agrolib/crop/crop.cpp +++ b/agrolib/crop/crop.cpp @@ -2,7 +2,7 @@ \file crop.cpp \abstract - Crop class functions + Crop development (Crit3DCrop class) \authors Fausto Tomei ftomei@arpae.it @@ -49,7 +49,7 @@ Crit3DCrop::Crit3DCrop() void Crit3DCrop::clear() { idCrop = ""; - type = HERBACEOUS_ANNUAL; + type = BARESOIL; roots.clear(); @@ -107,21 +107,36 @@ void Crit3DCrop::initialize(double latitude, unsigned int nrLayers, double total // initialize root depth roots.rootDepth = 0; - if (totalSoilDepth == 0 || roots.rootDepthMax < totalSoilDepth) - roots.actualRootDepthMax = roots.rootDepthMax; + if (isBareSoil()) + { + roots.rootDepthMax = 0; + roots.actualRootDepthMax = 0; + } else - roots.actualRootDepthMax = totalSoilDepth; + { + if (totalSoilDepth == 0 || roots.rootDepthMax < totalSoilDepth) + { + roots.actualRootDepthMax = roots.rootDepthMax; + } + else + { + roots.actualRootDepthMax = totalSoilDepth; + } + } degreeDays = 0; if (latitude > 0) + { doyStartSenescence = 305; + } else + { doyStartSenescence = 120; + } LAIstartSenescence = NODATA; currentSowingDoy = NODATA; - daysSinceIrrigation = NODATA; // check if the crop is living @@ -134,7 +149,7 @@ void Crit3DCrop::initialize(double latitude, unsigned int nrLayers, double total } else { - isLiving = true; + isLiving = !isBareSoil(); } resetCrop(nrLayers); @@ -399,7 +414,7 @@ bool Crit3DCrop::needReset(Crit3DDate myDate, double latitude, double waterTable void Crit3DCrop::resetCrop(unsigned int nrLayers) { // roots - if (! isRootStatic()) + if (! isBareSoil() && ! isRootStatic()) { for (unsigned int i = 0; i < nrLayers; i++) roots.rootDensity[i] = 0; @@ -855,10 +870,13 @@ speciesType getCropType(std::string cropType) return FALLOW_ANNUAL; else if (cropType == "tree" || cropType == "fruit_tree") return TREE; + else if (cropType == "bare" || cropType == "bare_soil") + return BARESOIL; else return HERBACEOUS_ANNUAL; } + std::string getCropTypeString(speciesType cropType) { switch (cropType) @@ -877,6 +895,8 @@ std::string getCropTypeString(speciesType cropType) return "fallow_annual"; case TREE: return "tree"; + case BARESOIL: + return "bare_soil"; } return "No crop type"; diff --git a/agrolib/crop/crop.h b/agrolib/crop/crop.h index 13dc588a..4619c432 100644 --- a/agrolib/crop/crop.h +++ b/agrolib/crop/crop.h @@ -11,8 +11,8 @@ #include "root.h" #endif - enum speciesType {HERBACEOUS_ANNUAL, HERBACEOUS_PERENNIAL, HORTICULTURAL, GRASS, TREE, FALLOW, FALLOW_ANNUAL}; - #define NR_CROP_SPECIES 7 + enum speciesType {HERBACEOUS_ANNUAL, HERBACEOUS_PERENNIAL, HORTICULTURAL, GRASS, TREE, FALLOW, FALLOW_ANNUAL, BARESOIL}; + #define NR_CROP_SPECIES 8 /*! * \brief The Crit3DCrop class @@ -43,8 +43,8 @@ /*! * water need */ - double kcMax; /*!< [-] */ - int psiLeaf; /*!< [cm] */ + double kcMax; /*!< [-] maximum crop coefficient */ + int psiLeaf; /*!< [cm] maximum water suction potential */ double stressTolerance; /*!< [-] */ double fRAW; /*!< [-] fraction of Readily Available Water */ @@ -81,6 +81,9 @@ bool isSowingCrop() const; bool isRootStatic() const; + bool isBareSoil() const + { return (type == BARESOIL); } + double getDailyDegreeIncrease(double tmin, double tmax, int doy); void initialize(double latitude, unsigned int nrLayers, double totalSoilDepth, int currentDoy); diff --git a/agrolib/crop/cropDbTools.cpp b/agrolib/crop/cropDbTools.cpp index 6904172b..2bf3b7be 100644 --- a/agrolib/crop/cropDbTools.cpp +++ b/agrolib/crop/cropDbTools.cpp @@ -87,19 +87,18 @@ bool loadCropParameters(const QSqlDatabase &dbCrop, QString idCrop, Crit3DCrop & myCrop.kcMax = query.value("kc_max").toDouble(); // [cm] if (! getValue(query.value("psi_leaf"), &(myCrop.psiLeaf))) + { + // default myCrop.psiLeaf = 16000; + } myCrop.stressTolerance = query.value("stress_tolerance").toDouble(); // fraction of Readily Available Water if (! getValue(query.value("raw_fraction"), &(myCrop.fRAW))) { - // old version - if (! getValue(query.value("frac_read_avail_water_max"), &(myCrop.fRAW))) - { - errorStr = "Missing RAW_fraction for crop: " + idCropString; - return false; - } + // default + myCrop.fRAW = 0.6; } // IRRIGATION @@ -109,17 +108,25 @@ bool loadCropParameters(const QSqlDatabase &dbCrop, QString idCrop, Crit3DCrop & getValue(query.value("doy_start_irrigation"), &(myCrop.doyStartIrrigation)); getValue(query.value("doy_end_irrigation"), &(myCrop.doyEndIrrigation)); - // key value for irrigation + // irrigation volume [mm day-1] if (! getValue(query.value("irrigation_volume"), &(myCrop.irrigationVolume))) + { + // default: no irrigation myCrop.irrigationVolume = 0; + } // LAI grass if (! getValue(query.value("lai_grass"), &(myCrop.LAIgrass))) + { myCrop.LAIgrass = 0; + } - // max surface puddle + // max surface puddle [mm] if (! getValue(query.value("max_height_surface_puddle"), &(myCrop.maxSurfacePuddle))) - myCrop.maxSurfacePuddle = 0; + { + // default: 5 mm + myCrop.maxSurfacePuddle = 5; + } return true; } @@ -156,31 +163,69 @@ bool updateCropLAIparam(QSqlDatabase &dbCrop, const Crit3DCrop &myCrop, QString "lai_curve_factor_a = :lai_curve_factor_a, lai_curve_factor_b = :lai_curve_factor_b, " "kc_max = :kc_max WHERE id_crop = :id_crop"); - if (myCrop.sowingDoy != NODATA) + if (myCrop.isBareSoil()) { - qry.bindValue(":sowing_doy", myCrop.sowingDoy); - qry.bindValue(":max_cycle", myCrop.plantCycle); + qry.bindValue(":sowing_doy", ""); + qry.bindValue(":max_cycle", ""); + qry.bindValue(":lai_grass", ""); + qry.bindValue(":lai_min", ""); + qry.bindValue(":lai_max", ""); + qry.bindValue(":thermal_threshold", ""); + qry.bindValue(":upper_thermal_threshold", ""); + qry.bindValue(":degree_days_lai_increase", ""); + qry.bindValue(":degree_days_lai_decrease", ""); + qry.bindValue(":lai_curve_factor_a", ""); + qry.bindValue(":lai_curve_factor_b", ""); + qry.bindValue(":kc_max", ""); } else { - qry.bindValue(":sowing_doy", ""); - qry.bindValue(":max_cycle", 365); + if (myCrop.sowingDoy != NODATA) + { + qry.bindValue(":sowing_doy", myCrop.sowingDoy); + qry.bindValue(":max_cycle", myCrop.plantCycle); + } + else + { + qry.bindValue(":sowing_doy", ""); + qry.bindValue(":max_cycle", 365); + } + + if (myCrop.LAIgrass != NODATA) + { + qry.bindValue(":lai_grass", myCrop.LAIgrass); + } + else + { + qry.bindValue(":lai_grass", ""); + } + + if (myCrop.degreeDaysEmergence != 0 && myCrop.degreeDaysEmergence != NODATA) + { + qry.bindValue(":degree_days_emergence", myCrop.degreeDaysEmergence); + } + else + { + qry.bindValue(":degree_days_emergence", ""); + } + + qry.bindValue(":lai_min", myCrop.LAImin); + qry.bindValue(":lai_max", myCrop.LAImax); + + qry.bindValue(":thermal_threshold", myCrop.thermalThreshold); + qry.bindValue(":upper_thermal_threshold", myCrop.upperThermalThreshold); + + qry.bindValue(":degree_days_lai_increase", myCrop.degreeDaysIncrease); + qry.bindValue(":degree_days_lai_decrease", myCrop.degreeDaysDecrease); + + qry.bindValue(":lai_curve_factor_a", myCrop.LAIcurve_a); + qry.bindValue(":lai_curve_factor_b", myCrop.LAIcurve_b); + qry.bindValue(":kc_max", myCrop.kcMax); } - qry.bindValue(":lai_min", myCrop.LAImin); - qry.bindValue(":lai_max", myCrop.LAImax); - qry.bindValue(":lai_grass", myCrop.LAIgrass); - qry.bindValue(":thermal_threshold", myCrop.thermalThreshold); - qry.bindValue(":upper_thermal_threshold", myCrop.upperThermalThreshold); - qry.bindValue(":degree_days_emergence", myCrop.degreeDaysEmergence); - qry.bindValue(":degree_days_lai_increase", myCrop.degreeDaysIncrease); - qry.bindValue(":degree_days_lai_decrease", myCrop.degreeDaysDecrease); - qry.bindValue(":lai_curve_factor_a", myCrop.LAIcurve_a); - qry.bindValue(":lai_curve_factor_b", myCrop.LAIcurve_b); - qry.bindValue(":kc_max", myCrop.kcMax); qry.bindValue(":id_crop", QString::fromStdString(myCrop.idCrop)); - if( !qry.exec() ) + if( ! qry.exec() ) { errorStr = qry.lastError().text(); return false; @@ -200,11 +245,30 @@ bool updateCropRootparam(QSqlDatabase &dbCrop, const Crit3DCrop &myCrop, QString " degree_days_root_increase = :degree_days_root_increase" " WHERE id_crop = :id_crop"); - qry.bindValue(":root_shape", root::getRootDistributionNumber(myCrop.roots.rootShape)); - qry.bindValue(":root_depth_zero", myCrop.roots.rootDepthMin); - qry.bindValue(":root_depth_max", myCrop.roots.rootDepthMax); - qry.bindValue(":root_shape_deformation", myCrop.roots.shapeDeformation); - qry.bindValue(":degree_days_root_increase", myCrop.roots.degreeDaysRootGrowth); + if (myCrop.isBareSoil()) + { + qry.bindValue(":root_shape", ""); + qry.bindValue(":root_depth_zero", ""); + qry.bindValue(":root_depth_max", ""); + qry.bindValue(":root_shape_deformation", ""); + qry.bindValue(":degree_days_root_increase", ""); + } + else + { + qry.bindValue(":root_shape", root::getRootDistributionNumber(myCrop.roots.rootShape)); + qry.bindValue(":root_depth_zero", myCrop.roots.rootDepthMin); + qry.bindValue(":root_depth_max", myCrop.roots.rootDepthMax); + qry.bindValue(":root_shape_deformation", myCrop.roots.shapeDeformation); + + if (myCrop.roots.degreeDaysRootGrowth != NODATA) + { + qry.bindValue(":degree_days_root_increase", myCrop.roots.degreeDaysRootGrowth); + } + else + { + qry.bindValue(":degree_days_root_increase", ""); + } + } qry.bindValue(":id_crop", QString::fromStdString(myCrop.idCrop)); @@ -213,6 +277,7 @@ bool updateCropRootparam(QSqlDatabase &dbCrop, const Crit3DCrop &myCrop, QString errorStr = qry.lastError().text(); return false; } + return true; } @@ -226,12 +291,12 @@ bool updateCropIrrigationparam(QSqlDatabase &dbCrop, const Crit3DCrop &myCrop, Q "psi_leaf = :psi_leaf, raw_fraction = :raw_fraction, stress_tolerance = :stress_tolerance" " WHERE id_crop = :id_crop"); - if (myCrop.irrigationVolume == 0) + if (myCrop.irrigationVolume == 0 || myCrop.isBareSoil()) { - qry.bindValue(":irrigation_shift", QVariant(QVariant::String)); + qry.bindValue(":irrigation_shift", ""); qry.bindValue(":irrigation_volume", 0); - qry.bindValue(":degree_days_start_irrigation", QVariant(QVariant::String)); - qry.bindValue(":degree_days_end_irrigation", QVariant(QVariant::String)); + qry.bindValue(":degree_days_start_irrigation", ""); + qry.bindValue(":degree_days_end_irrigation", ""); } else { @@ -241,9 +306,18 @@ bool updateCropIrrigationparam(QSqlDatabase &dbCrop, const Crit3DCrop &myCrop, Q qry.bindValue(":degree_days_end_irrigation", myCrop.degreeDaysEndIrrigation); } - qry.bindValue(":psi_leaf", myCrop.psiLeaf); - qry.bindValue(":raw_fraction", myCrop.fRAW); - qry.bindValue(":stress_tolerance", myCrop.stressTolerance); + if (myCrop.isBareSoil() ) + { + qry.bindValue(":psi_leaf", ""); + qry.bindValue(":raw_fraction", ""); + qry.bindValue(":stress_tolerance", ""); + } + else + { + qry.bindValue(":psi_leaf", myCrop.psiLeaf); + qry.bindValue(":raw_fraction", myCrop.fRAW); + qry.bindValue(":stress_tolerance", myCrop.stressTolerance); + } qry.bindValue(":id_crop", QString::fromStdString(myCrop.idCrop)); diff --git a/agrolib/crop/landUnit.cpp b/agrolib/crop/landUnit.cpp index 15baddc8..d39f754d 100644 --- a/agrolib/crop/landUnit.cpp +++ b/agrolib/crop/landUnit.cpp @@ -59,13 +59,3 @@ bool loadLandUnitList(const QSqlDatabase &dbCrop, std::vector &l return true; } - - -int getLandUnitIndex(const std::vector &landUnitList, int idLandUnit) -{ - for (int index = 0; index < landUnitList.size(); index++) - if (landUnitList[index].id == idLandUnit) - return index; - - return NODATA; -} diff --git a/agrolib/crop/landUnit.h b/agrolib/crop/landUnit.h index be563b3d..fb11f46c 100644 --- a/agrolib/crop/landUnit.h +++ b/agrolib/crop/landUnit.h @@ -23,7 +23,5 @@ bool loadLandUnitList(const QSqlDatabase &dbCrop, std::vector &landUnitList, QString &errorStr); - int getLandUnitIndex(const std::vector &landUnitList, int idLandUnit); - #endif // LANDUNIT_H diff --git a/agrolib/crop/root.cpp b/agrolib/crop/root.cpp index dbf77110..3eb4ad0a 100644 --- a/agrolib/crop/root.cpp +++ b/agrolib/crop/root.cpp @@ -497,7 +497,7 @@ namespace root const std::vector &layerDepth, const std::vector &layerThickness) { // check soil - if (nrLayers == 0) + if (nrLayers <= 1) { myCrop.roots.firstRootLayer = NODATA; myCrop.roots.lastRootLayer = NODATA; diff --git a/agrolib/dbMeteoGrid/dbMeteoGrid.cpp b/agrolib/dbMeteoGrid/dbMeteoGrid.cpp index 602b34b5..22f804c7 100644 --- a/agrolib/dbMeteoGrid/dbMeteoGrid.cpp +++ b/agrolib/dbMeteoGrid/dbMeteoGrid.cpp @@ -37,14 +37,14 @@ bool Crit3DMeteoGridDbHandler::parseXMLFile(QString xmlFileName, QDomDocument* x return (false); } - QString myError; + QString errorStr; int myErrLine, myErrColumn; - if (!xmlDoc->setContent(&myFile, &myError, &myErrLine, &myErrColumn)) + if (!xmlDoc->setContent(&myFile, &errorStr, &myErrLine, &myErrColumn)) { *error = "Parse xml failed:" + xmlFileName + " Row: " + QString::number(myErrLine) + " - Column: " + QString::number(myErrColumn) - + "\n" + myError; + + "\n" + errorStr; myFile.close(); return(false); } @@ -54,11 +54,11 @@ bool Crit3DMeteoGridDbHandler::parseXMLFile(QString xmlFileName, QDomDocument* x } -bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myError) +bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *errorStr) { QDomDocument xmlDoc; - if (! parseXMLFile(xmlFileName, &xmlDoc, myError)) return false; + if (! parseXMLFile(xmlFileName, &xmlDoc, errorStr)) return false; QDomNode child; QDomNode secondChild; @@ -86,7 +86,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing provider"; + *errorStr = "Missing provider"; return false; } _connection.provider = child.toElement().text(); @@ -97,7 +97,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing server"; + *errorStr = "Missing server"; return false; } _connection.server = child.toElement().text(); @@ -108,7 +108,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing name"; + *errorStr = "Missing name"; return false; } _connection.name = child.toElement().text(); @@ -119,7 +119,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing user"; + *errorStr = "Missing user"; return false; } _connection.user = child.toElement().text(); @@ -130,7 +130,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing password"; + *errorStr = "Missing password"; return false; } _connection.password = child.toElement().text(); @@ -153,7 +153,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro } else { - *myError = "Invalid isRegular attribute"; + *errorStr = "Invalid isRegular attribute"; return false; } @@ -167,7 +167,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro } else { - *myError = "Invalid isutm attribute"; + *errorStr = "Invalid isutm attribute"; return false; } @@ -181,7 +181,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro } else { - *myError = "Invalid istin attribute"; + *errorStr = "Invalid istin attribute"; return false; } @@ -196,7 +196,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro } else { - *myError = "Invalid isfixedfields attribute"; + *errorStr = "Invalid isfixedfields attribute"; return false; } @@ -236,7 +236,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing XLL"; + *errorStr = "Missing XLL"; return false; } header.llCorner.longitude = child.toElement().text().toFloat(); @@ -245,7 +245,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing YLL"; + *errorStr = "Missing YLL"; return false; } header.llCorner.latitude = child.toElement().text().toFloat(); @@ -254,7 +254,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing NROWS"; + *errorStr = "Missing NROWS"; return false; } header.nrRows = child.toElement().text().toInt(); @@ -264,7 +264,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing NCOLS"; + *errorStr = "Missing NCOLS"; return false; } header.nrCols = child.toElement().text().toInt(); @@ -274,7 +274,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing XWIDTH"; + *errorStr = "Missing XWIDTH"; return false; } header.dx = child.toElement().text().toFloat(); @@ -283,7 +283,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { if (child.toElement().text().isEmpty()) { - *myError = "Missing YWIDTH"; + *errorStr = "Missing YWIDTH"; return false; } header.dy = child.toElement().text().toFloat(); @@ -291,7 +291,6 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro child = child.nextSibling(); } _gridStructure.setHeader(header); - } else if (ancestor.toElement().tagName().toUpper() == "TABLEDAILY") @@ -329,17 +328,14 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { mySecondTag = secondChild.toElement().tagName().toUpper(); - if (mySecondTag == "VARFIELD") { _tableDaily.varcode[_tableDaily.varcode.size()-1].varField = secondChild.toElement().text(); - } else if (mySecondTag == "VARCODE") { _tableDaily.varcode[_tableDaily.varcode.size()-1].varCode = secondChild.toElement().text().toInt(); - } else if (mySecondTag == "VARPRAGANAME") @@ -395,17 +391,14 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { mySecondTag = secondChild.toElement().tagName().toUpper(); - if (mySecondTag == "VARFIELD") { _tableHourly.varcode[_tableHourly.varcode.size()-1].varField = secondChild.toElement().text(); - } else if (mySecondTag == "VARCODE") { _tableHourly.varcode[_tableHourly.varcode.size()-1].varCode = secondChild.toElement().text().toInt(); - } else if (mySecondTag == "VARPRAGANAME") @@ -444,17 +437,14 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro { mySecondTag = secondChild.toElement().tagName().toUpper(); - if (mySecondTag == "VARFIELD") { _tableMonthly.varcode[_tableMonthly.varcode.size()-1].varField = secondChild.toElement().text(); - } else if (mySecondTag == "VARCODE") { _tableMonthly.varcode[_tableMonthly.varcode.size()-1].varCode = secondChild.toElement().text().toInt(); - } else if (mySecondTag == "VARPRAGANAME") @@ -479,7 +469,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro } xmlDoc.clear(); - if (!checkXML(myError)) + if (!checkXML(errorStr)) { return false; } @@ -496,9 +486,8 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro catch (const std::out_of_range& oor) { QString errMess = QString("%1 does not exist" ).arg(_tableDaily.varcode[i].varPragaName); - *myError = oor.what() + errMess; + *errorStr = oor.what() + errMess; } - } for (unsigned int i=0; i < _tableHourly.varcode.size(); i++) @@ -512,7 +501,7 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro catch (const std::out_of_range& oor) { QString errMess = QString("%1 does not exist" ).arg(_tableHourly.varcode[i].varPragaName); - *myError = oor.what() + errMess; + *errorStr = oor.what() + errMess; } } @@ -527,17 +516,17 @@ bool Crit3DMeteoGridDbHandler::parseXMLGrid(QString xmlFileName, QString *myErro catch (const std::out_of_range& oor) { QString errMess = QString("%1 does not exist" ).arg(_tableMonthly.varcode[i].varPragaName); - *myError = oor.what() + errMess; + *errorStr = oor.what() + errMess; } } _meteoGrid->setGridStructure(_gridStructure); - _meteoGrid->initMeteoPoints(nRow, nCol); return true; } + void Crit3DMeteoGridDbHandler::initMapMySqlVarType() { _mapDailyMySqlVarType[dailyAirTemperatureMin] = "float(4,1)"; @@ -570,36 +559,35 @@ void Crit3DMeteoGridDbHandler::initMapMySqlVarType() _mapHourlyMySqlVarType[windVectorDirection] = "smallint(3) UNSIGNED"; _mapHourlyMySqlVarType[referenceEvapotranspiration] = "float(3,1) UNSIGNED"; _mapHourlyMySqlVarType[leafWetness] = "tinyint(3) UNSIGNED"; - } -bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) -{ +bool Crit3DMeteoGridDbHandler::checkXML(QString *errorStr) +{ /* connection */ if (_connection.provider.isNull() || _connection.provider.isEmpty()) { - *myError = "Missing connection provider"; + *errorStr = "Missing connection provider"; return false; } if (_connection.server.isNull() || _connection.server.isEmpty()) { - *myError = "Missing connection server"; + *errorStr = "Missing connection server"; return false; } if (_connection.name.isNull() || _connection.name.isEmpty()) { - *myError = "Missing connection name"; + *errorStr = "Missing connection name"; return false; } if (_connection.user.isNull() || _connection.user.isEmpty()) { - *myError = "Missing connection user"; + *errorStr = "Missing connection user"; return false; } if (_connection.password.isNull() || _connection.password.isEmpty()) { - *myError = "Missing connection password"; + *errorStr = "Missing connection password"; return false; } @@ -607,38 +595,38 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) if (_gridStructure.header().llCorner.longitude == NODATA) { - *myError = "Error missing xll tag"; + *errorStr = "Error missing xll tag"; return false; } if (_gridStructure.header().llCorner.latitude == NODATA) { - *myError = "Error missing yll tag"; + *errorStr = "Error missing yll tag"; return false; } if (_gridStructure.header().nrRows == NODATA) { - *myError = "Error missing nrows tag"; + *errorStr = "Error missing nrows tag"; return false; } if (_gridStructure.header().nrCols == NODATA) { - *myError = "Error missing ncols tag"; + *errorStr = "Error missing ncols tag"; return false; } if (_gridStructure.header().dx == NODATA) { - *myError = "Error missing xwidth tag"; + *errorStr = "Error missing xwidth tag"; return false; } if (_gridStructure.header().dy == NODATA) { - *myError = "Error missing ywidth tag"; + *errorStr = "Error missing ywidth tag"; return false; } if (_gridStructure.isUTM() == true && _gridStructure.header().dx != _gridStructure.header().dy ) { - *myError = "UTM grid with dx != dy"; + *errorStr = "UTM grid with dx != dy"; return false; } @@ -647,13 +635,13 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) { if (_tableDaily.fieldTime.isNull() || _tableDaily.fieldTime.isEmpty()) { - *myError = "Missing table Daily fieldTime"; + *errorStr = "Missing table Daily fieldTime"; return false; } if (_tableDaily.varcode.size() < 1 && _tableHourly.varcode.size() < 1) { - *myError = "Missing daily and hourly var code"; + *errorStr = "Missing daily and hourly var code"; return false; } @@ -661,17 +649,17 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) { if (_tableDaily.varcode[i].varCode == NODATA) { - *myError = "Missing daily var code"; + *errorStr = "Missing daily var code"; return false; } if (_tableDaily.varcode[i].varPragaName.isNull() || _tableDaily.varcode[i].varPragaName.isEmpty()) { - *myError = "Missing daily varPragaName"; + *errorStr = "Missing daily varPragaName"; return false; } if (_gridStructure.isFixedFields() == true && (_tableDaily.varcode[i].varField.isNull() || _tableDaily.varcode[i].varField.isEmpty()) ) { - *myError = "Fixed Field: Missing daily varField"; + *errorStr = "Fixed Field: Missing daily varField"; return false; } } @@ -682,7 +670,7 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) { if (_tableHourly.fieldTime.isNull() || _tableHourly.fieldTime.isEmpty()) { - *myError = "Missing table Hourly fieldTime"; + *errorStr = "Missing table Hourly fieldTime"; return false; } @@ -690,17 +678,17 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) { if (_tableHourly.varcode[i].varCode == NODATA) { - *myError = "Missing daily var code"; + *errorStr = "Missing daily var code"; return false; } if (_tableHourly.varcode[i].varPragaName.isNull() || _tableHourly.varcode[i].varPragaName.isEmpty()) { - *myError = "Missing daily varPragaName"; + *errorStr = "Missing daily varPragaName"; return false; } if (_gridStructure.isFixedFields() == true && (_tableHourly.varcode[i].varField.isNull() || _tableHourly.varcode[i].varField.isEmpty()) ) { - *myError = "Fixed Field: Missing daily varField"; + *errorStr = "Fixed Field: Missing daily varField"; return false; } } @@ -713,12 +701,12 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) { if (_tableMonthly.varcode[i].varCode == NODATA) { - *myError = "Missing monthly var code"; + *errorStr = "Missing monthly var code"; return false; } if (_tableMonthly.varcode[i].varPragaName.isNull() || _tableMonthly.varcode[i].varPragaName.isEmpty()) { - *myError = "Missing monthly varPragaName"; + *errorStr = "Missing monthly varPragaName"; return false; } } @@ -727,32 +715,34 @@ bool Crit3DMeteoGridDbHandler::checkXML(QString *myError) return true; } + int Crit3DMeteoGridDbHandler::getDailyVarCode(meteoVariable meteoGridDailyVar) { - int varCode = NODATA; + //check if (meteoGridDailyVar == noMeteoVar) { return varCode; } + if (_gridDailyVar.empty()) { qDebug() << "_gridDailyVar is empty"; return varCode; } + if(_gridDailyVar.contains(meteoGridDailyVar)) { varCode = _gridDailyVar[meteoGridDailyVar]; } return varCode; - } + QString Crit3DMeteoGridDbHandler::getDailyVarField(meteoVariable meteoGridDailyVar) { - QString varField = ""; //check if (meteoGridDailyVar == noMeteoVar) @@ -769,9 +759,9 @@ QString Crit3DMeteoGridDbHandler::getDailyVarField(meteoVariable meteoGridDailyV } return varField; - } + meteoVariable Crit3DMeteoGridDbHandler::getDailyVarEnum(int varCode) { if (varCode == NODATA) @@ -794,7 +784,6 @@ meteoVariable Crit3DMeteoGridDbHandler::getDailyVarEnum(int varCode) meteoVariable Crit3DMeteoGridDbHandler::getDailyVarFieldEnum(QString varField) { - if (varField == "") { return noMeteoVar; @@ -812,53 +801,57 @@ meteoVariable Crit3DMeteoGridDbHandler::getDailyVarFieldEnum(QString varField) return noMeteoVar; } + int Crit3DMeteoGridDbHandler::getHourlyVarCode(meteoVariable meteoGridHourlyVar) { - int varCode = NODATA; + //check if (meteoGridHourlyVar == noMeteoVar) { return varCode; } + if (_gridHourlyVar.empty()) { return varCode; } + if(_gridHourlyVar.contains(meteoGridHourlyVar)) { varCode = _gridHourlyVar[meteoGridHourlyVar]; } return varCode; - } + QString Crit3DMeteoGridDbHandler::getHourlyVarField(meteoVariable meteoGridHourlyVar) { - QString varField = ""; + //check if (meteoGridHourlyVar == noMeteoVar) { return varField; } + if (_gridHourlyVarField.empty()) { return varField; } + if(_gridHourlyVarField.contains(meteoGridHourlyVar)) { varField = _gridHourlyVarField[meteoGridHourlyVar]; } return varField; - } + meteoVariable Crit3DMeteoGridDbHandler::getHourlyVarEnum(int varCode) { - if (varCode == NODATA) { return noMeteoVar; @@ -874,12 +867,11 @@ meteoVariable Crit3DMeteoGridDbHandler::getHourlyVarEnum(int varCode) } return noMeteoVar; - } + meteoVariable Crit3DMeteoGridDbHandler::getHourlyVarFieldEnum(QString varField) { - if (varField == "") { return noMeteoVar; @@ -895,9 +887,9 @@ meteoVariable Crit3DMeteoGridDbHandler::getHourlyVarFieldEnum(QString varField) } return noMeteoVar; - } + int Crit3DMeteoGridDbHandler::getMonthlyVarCode(meteoVariable meteoGridMonthlyVar) { @@ -917,9 +909,9 @@ int Crit3DMeteoGridDbHandler::getMonthlyVarCode(meteoVariable meteoGridMonthlyVa } return varCode; - } + QString Crit3DMeteoGridDbHandler::getMonthlyVarField(meteoVariable meteoGridMonthlyVar) { @@ -965,7 +957,6 @@ meteoVariable Crit3DMeteoGridDbHandler::getMonthlyVarEnum(int varCode) meteoVariable Crit3DMeteoGridDbHandler::getMonthlyVarFieldEnum(QString varField) { - if (varField == "") { return noMeteoVar; @@ -981,12 +972,11 @@ meteoVariable Crit3DMeteoGridDbHandler::getMonthlyVarFieldEnum(QString varField) } return noMeteoVar; - } + std::string Crit3DMeteoGridDbHandler::getDailyPragaName(meteoVariable meteoVar) { - std::map::const_iterator it; std::string key = ""; @@ -998,12 +988,13 @@ std::string Crit3DMeteoGridDbHandler::getDailyPragaName(meteoVariable meteoVar) break; } } + return key; } + std::string Crit3DMeteoGridDbHandler::getHourlyPragaName(meteoVariable meteoVar) { - std::map::const_iterator it; std::string key = ""; @@ -1015,12 +1006,13 @@ std::string Crit3DMeteoGridDbHandler::getHourlyPragaName(meteoVariable meteoVar) break; } } + return key; } + std::string Crit3DMeteoGridDbHandler::getMonthlyPragaName(meteoVariable meteoVar) { - std::map::const_iterator it; std::string key = ""; @@ -1032,13 +1024,13 @@ std::string Crit3DMeteoGridDbHandler::getMonthlyPragaName(meteoVariable meteoVar break; } } + return key; } -bool Crit3DMeteoGridDbHandler::openDatabase(QString *myError) +bool Crit3DMeteoGridDbHandler::openDatabase(QString *errorStr) { - if (_connection.provider.toUpper() == "MYSQL") { _db = QSqlDatabase::addDatabase("QMYSQL", "grid"); @@ -1051,16 +1043,16 @@ bool Crit3DMeteoGridDbHandler::openDatabase(QString *myError) if (!_db.open()) { - *myError = "Connection with database fail.\n" + _db.lastError().text(); + *errorStr = "Connection with database fail.\n" + _db.lastError().text(); return false; } - else - return true; + + return true; } -bool Crit3DMeteoGridDbHandler::newDatabase(QString *myError) -{ +bool Crit3DMeteoGridDbHandler::newDatabase(QString *errorStr) +{ if (_connection.provider.toUpper() == "MYSQL") { _db = QSqlDatabase::addDatabase("QMYSQL"); @@ -1077,20 +1069,22 @@ bool Crit3DMeteoGridDbHandler::newDatabase(QString *myError) if (!query.exec()) { - *myError = "MySQL error:" + query.lastError().text(); + *errorStr = "MySQL error:" + query.lastError().text(); return false; } + _db.setDatabaseName(_connection.name); if (!_db.open()) { - *myError = "Connection with database fail.\n" + _db.lastError().text(); + *errorStr = "Connection with database fail.\n" + _db.lastError().text(); return false; } - else - return true; + + return true; } -bool Crit3DMeteoGridDbHandler::deleteDatabase(QString *myError) + +bool Crit3DMeteoGridDbHandler::deleteDatabase(QString *errorStr) { QSqlQuery query(_db); @@ -1098,15 +1092,16 @@ bool Crit3DMeteoGridDbHandler::deleteDatabase(QString *myError) if (!query.exec()) { - *myError = "MySQL error:" + query.lastError().text(); + *errorStr = "MySQL error:" + query.lastError().text(); return false; } + return true; } -bool Crit3DMeteoGridDbHandler::newDatabase(QString *myError, QString connectionName) -{ +bool Crit3DMeteoGridDbHandler::newDatabase(QString *errorStr, QString connectionName) +{ if (_connection.provider.toUpper() == "MYSQL") { _db = QSqlDatabase::addDatabase("QMYSQL", connectionName); @@ -1123,22 +1118,23 @@ bool Crit3DMeteoGridDbHandler::newDatabase(QString *myError, QString connectionN if (!query.exec()) { - *myError = "MySQL error:" + query.lastError().text(); + *errorStr = "MySQL error:" + query.lastError().text(); return false; } + _db.setDatabaseName(_connection.name); if (!_db.open()) { - *myError = "Connection with database fail.\n" + _db.lastError().text(); + *errorStr = "Connection with database fail.\n" + _db.lastError().text(); return false; } - else - return true; + + return true; } -bool Crit3DMeteoGridDbHandler::openDatabase(QString *myError, QString connectionName) -{ +bool Crit3DMeteoGridDbHandler::openDatabase(QString *errorStr, QString connectionName) +{ if (_connection.provider.toUpper() == "MYSQL") { _db = QSqlDatabase::addDatabase("QMYSQL", connectionName); @@ -1151,11 +1147,11 @@ bool Crit3DMeteoGridDbHandler::openDatabase(QString *myError, QString connection if (!_db.open()) { - *myError = "Connection with database fail.\n" + _db.lastError().text(); + *errorStr = "Connection with database fail.\n" + _db.lastError().text(); return false; } - else - return true; + + return true; } @@ -1170,7 +1166,7 @@ void Crit3DMeteoGridDbHandler::closeDatabase() } } -bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) +bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *errorStr) { QSqlQuery qry(_db); int row, col, active, height; @@ -1179,7 +1175,7 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) qry.prepare( "SHOW TABLES LIKE '%ells%roperties'" ); if( !qry.exec() ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -1192,7 +1188,7 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -1203,7 +1199,7 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) if (! getValue(qry.value("Code"), &code)) { - *myError = "Missing data: Code"; + *errorStr = "Missing data: Code"; return false; } @@ -1215,13 +1211,13 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) if (! getValue(qry.value("Row"), &row)) { - *myError = "Missing data: Row"; + *errorStr = "Missing data: Row"; return false; } if (! getValue(qry.value("Col"), &col)) { - *myError = "Missing data: Col"; + *errorStr = "Missing data: Col"; return false; } @@ -1237,7 +1233,7 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) if (! getValue(qry.value("Active"), &active)) { - *myError = "Missing data: Active"; + *errorStr = "Missing data: Active"; return false; } @@ -1248,7 +1244,7 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) } else { - *myError = "Row or Col > nrRows or nrCols"; + *errorStr = "Row or Col > nrRows or nrCols"; return false; } } @@ -1257,7 +1253,7 @@ bool Crit3DMeteoGridDbHandler::loadCellProperties(QString *myError) } -bool Crit3DMeteoGridDbHandler::newCellProperties(QString *myError) +bool Crit3DMeteoGridDbHandler::newCellProperties(QString *errorStr) { QSqlQuery qry(_db); QString table = "CellsProperties"; @@ -1267,14 +1263,14 @@ bool Crit3DMeteoGridDbHandler::newCellProperties(QString *myError) if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } return true; } -bool Crit3DMeteoGridDbHandler::writeCellProperties(QString *myError, int nRow, int nCol) +bool Crit3DMeteoGridDbHandler::writeCellProperties(QString *errorStr, int nRow, int nCol) { QSqlQuery qry(_db); QString table = "CellsProperties"; @@ -1295,21 +1291,21 @@ bool Crit3DMeteoGridDbHandler::writeCellProperties(QString *myError, int nRow, i if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } return true; } -bool Crit3DMeteoGridDbHandler::activeAllCells(QString *myError) +bool Crit3DMeteoGridDbHandler::activeAllCells(QString *errorStr) { QSqlQuery qry(_db); qry.prepare( "UPDATE CellsProperties SET Active = 1" ); if( !qry.exec() ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -1318,14 +1314,14 @@ bool Crit3DMeteoGridDbHandler::activeAllCells(QString *myError) } } -bool Crit3DMeteoGridDbHandler::setActiveStateCellsInList(QString *myError, QList idList, bool activeState) +bool Crit3DMeteoGridDbHandler::setActiveStateCellsInList(QString *errorStr, QList idList, bool activeState) { QSqlQuery qry(_db); QString statement = QString("UPDATE CellsProperties SET Active = %1 WHERE `Code` IN ('%2')").arg(activeState).arg(idList.join("','")); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -1334,7 +1330,7 @@ bool Crit3DMeteoGridDbHandler::setActiveStateCellsInList(QString *myError, QList } } -bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString idMeteo) +bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *errorStr, QString idMeteo) { QSqlQuery qry(_db); int row, col, active, height; @@ -1343,7 +1339,7 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i qry.prepare( "SHOW TABLES LIKE '%ells%roperties'" ); if( !qry.exec() ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -1352,11 +1348,11 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i tableCellsProp = qry.value(0).toString(); } - QString statement = QString("SELECT * FROM `%1` WHERE `Code` = '%2'").arg(tableCellsProp).arg(idMeteo); + QString statement = QString("SELECT * FROM `%1` WHERE `Code` = '%2'").arg(tableCellsProp, idMeteo); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -1367,7 +1363,7 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i if (! getValue(qry.value("Code"), &code)) { - *myError = "Missing data: Code"; + *errorStr = "Missing data: Code"; return false; } @@ -1379,13 +1375,13 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i if (! getValue(qry.value("Row"), &row)) { - *myError = "Missing data: Row"; + *errorStr = "Missing data: Row"; return false; } if (! getValue(qry.value("Col"), &col)) { - *myError = "Missing data: Col"; + *errorStr = "Missing data: Col"; return false; } @@ -1401,7 +1397,7 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i if (! getValue(qry.value("Active"), &active)) { - *myError = "Missing data: Active"; + *errorStr = "Missing data: Active"; return false; } @@ -1412,7 +1408,7 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i } else { - *myError = "Row or Col > nrRows or nrCols"; + *errorStr = "Row or Col > nrRows or nrCols"; return false; } } @@ -1421,12 +1417,12 @@ bool Crit3DMeteoGridDbHandler::loadIdMeteoProperties(QString *myError, QString i } -bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) +bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &errorStr) { QList tableList = _db.tables(QSql::Tables); if (tableList.size() <= 1) { - myError = "No data."; + errorStr = "No data."; return false; } @@ -1437,7 +1433,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if (!_meteoGrid->findFirstActiveMeteoPoint(&id, &row, &col)) { - myError = "No active cells."; + errorStr = "No active cells."; return false; } @@ -1477,7 +1473,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if (!_meteoGrid->findFirstActiveMeteoPoint(&id, &row, &col)) { - myError = "active cell not found"; + errorStr = "active cell not found"; return false; } tableD = _tableDaily.prefix + QString::fromStdString(id) + _tableDaily.postFix; @@ -1489,7 +1485,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if ( qry.lastError().type() != QSqlError::NoError ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1509,7 +1505,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) } else { - myError = "Daily time field not found: " + _tableDaily.fieldTime; + errorStr = "Daily time field not found: " + _tableDaily.fieldTime; return false; } } @@ -1535,7 +1531,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if (! _meteoGrid->findFirstActiveMeteoPoint(&id, &row, &col)) { - myError = "active cell not found"; + errorStr = "active cell not found"; return false; } @@ -1548,7 +1544,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if ( qry.lastError().type() != QSqlError::NoError && qry.lastError().nativeErrorCode() != tableNotFoundError) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1569,7 +1565,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) } else { - myError = "Hourly time field not found: " + _tableHourly.fieldTime; + errorStr = "Hourly time field not found: " + _tableHourly.fieldTime; return false; } } @@ -1584,7 +1580,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if(! qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } @@ -1597,7 +1593,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if ( qry.lastError().type() != QSqlError::NoError ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1609,7 +1605,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) } else { - myError = "PragaYear field not found"; + errorStr = "PragaYear field not found"; return false; } } @@ -1618,7 +1614,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if ( qry.lastError().type() != QSqlError::NoError ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1629,7 +1625,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) } else { - myError = "PragaMonth field not found"; + errorStr = "PragaMonth field not found"; return false; } } @@ -1639,7 +1635,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if ( qry.lastError().type() != QSqlError::NoError ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1650,7 +1646,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) } else { - myError = "PragaMonth field not found"; + errorStr = "PragaMonth field not found"; return false; } } @@ -1695,7 +1691,7 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) if (_firstDate == noDate || _lastDate == noDate) { - myError = "Missing data."; + errorStr = "Missing data."; return false; } @@ -1703,15 +1699,15 @@ bool Crit3DMeteoGridDbHandler::updateMeteoGridDate(QString &myError) } -bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &myError, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate) +bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &errorStr, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate) { - myError = ""; + errorStr = ""; QString tableD = _tableDaily.prefix + meteoPointId + _tableDaily.postFix; unsigned row, col; - if ( !_meteoGrid->findMeteoPointFromId(&row, &col, meteoPointId.toStdString()) ) + if (! _meteoGrid->findMeteoPointFromId(&row, &col, meteoPointId.toStdString()) ) { - myError = "Missing meteoPoint id: " + meteoPointId; + errorStr = "Missing meteoPoint id: " + meteoPointId; return false; } @@ -1724,7 +1720,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &myError, const QString { if (firstDate > _lastDailyDate || lastDate < _firstDailyDate) { - myError = "Missing data in this time interval."; + errorStr = "Missing data in this time interval."; return false; } } @@ -1749,7 +1745,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &myError, const QString if(! qry.exec()) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } @@ -1765,14 +1761,14 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &myError, const QString { if (! getValue(qry.value(_tableDaily.fieldTime), &date)) { - myError = "Missing " + _tableDaily.fieldTime; + errorStr = "Missing " + _tableDaily.fieldTime; return false; } } if (! getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode"; + errorStr = "Missing VariableCode"; return false; } @@ -1780,7 +1776,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &myError, const QString if (! _meteoGrid->meteoPointPointer(row, col)->setMeteoPointValueD(getCrit3DDate(date), variable, value)) { - myError = "Error in setMeteoPointValueD"; + errorStr = "Error in setMeteoPointValueD"; return false; } } @@ -1789,15 +1785,15 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyData(QString &myError, const QString return true; } -bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &myError, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate) +bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &errorStr, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate) { - myError = ""; + errorStr = ""; QString tableD = _tableDaily.prefix + meteoPointId + _tableDaily.postFix; unsigned row, col; if ( !_meteoGrid->findMeteoPointFromId(&row, &col, meteoPointId.toStdString()) ) { - myError = "Missing meteoPoint id: " + meteoPointId; + errorStr = "Missing meteoPoint id: " + meteoPointId; return false; } @@ -1810,7 +1806,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &myError, const QS { if (firstDate > _lastDailyDate || lastDate < _firstDailyDate) { - myError = "Missing data in this time interval."; + errorStr = "Missing data in this time interval."; return false; } } @@ -1844,7 +1840,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &myError, const QS if(! qry.exec()) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } @@ -1860,14 +1856,14 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &myError, const QS { if (! getValue(qry.value(_tableDaily.fieldTime), &date)) { - myError = "Missing " + _tableDaily.fieldTime; + errorStr = "Missing " + _tableDaily.fieldTime; return false; } } if (! getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode"; + errorStr = "Missing VariableCode"; return false; } @@ -1875,7 +1871,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &myError, const QS if (! _meteoGrid->meteoPointPointer(row, col)->setMeteoPointValueD(getCrit3DDate(date), variable, value)) { - myError = "Error in setMeteoPointValueD"; + errorStr = "Error in setMeteoPointValueD"; return false; } } @@ -1885,37 +1881,37 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyMeteoPrec(QString &myError, const QS } -bool Crit3DMeteoGridDbHandler::loadGridDailyDataEnsemble(QString &myError, QString meteoPoint, int memberNr, QDate first, QDate last) +bool Crit3DMeteoGridDbHandler::loadGridDailyDataEnsemble(QString &errorStr, QString meteoPoint, int memberNr, QDate first, QDate last) { - myError = ""; + errorStr = ""; if (!_meteoGrid->gridStructure().isEnsemble()) { - myError = "Grid structure has not ensemble field"; + errorStr = "Grid structure has not ensemble field"; return false; } + QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPoint + _tableDaily.postFix; QDate date; int varCode; float value; - unsigned row; - unsigned col; + unsigned row, col; if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id"; + errorStr = "Missing MeteoPoint id"; return false; } int numberOfDays = first.daysTo(last) + 1; _meteoGrid->meteoPointPointer(row,col)->initializeObsDataD(numberOfDays, getCrit3DDate(first)); - QString statement = QString("SELECT * FROM `%1` WHERE `%2`>= '%3' AND `%2`<= '%4' AND MemberNr = '%5' ORDER BY `%2`").arg(tableD).arg(_tableDaily.fieldTime).arg(first.toString("yyyy-MM-dd")).arg(last.toString("yyyy-MM-dd")).arg(memberNr); + QString statement = QString("SELECT * FROM `%1` WHERE `%2`>= '%3' AND `%2`<= '%4' AND MemberNr = '%5' ORDER BY `%2`").arg(tableD, _tableDaily.fieldTime).arg(first.toString("yyyy-MM-dd")).arg(last.toString("yyyy-MM-dd")).arg(memberNr); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1924,19 +1920,19 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataEnsemble(QString &myError, QStri { if (!getValue(qry.value(_tableDaily.fieldTime), &date)) { - myError = "Missing fieldTime"; + errorStr = "Missing fieldTime"; return false; } if (!getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode"; + errorStr = "Missing VariableCode"; return false; } if (!getValue(qry.value("Value"), &value)) { - myError = "Missing Value"; + errorStr = "Missing Value"; } meteoVariable variable = getDailyVarEnum(varCode); @@ -1950,9 +1946,9 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataEnsemble(QString &myError, QStri } -bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &myError, QString meteoPoint, QDate first, QDate last) +bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &errorStr, QString meteoPoint, QDate first, QDate last) { - myError = ""; + errorStr = ""; QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPoint + _tableDaily.postFix; @@ -1964,7 +1960,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &myError, QS if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id"; + errorStr = "Missing MeteoPoint id"; return false; } @@ -1975,7 +1971,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &myError, QS _tableDaily.fieldTime, first.toString("yyyy-MM-dd"), last.toString("yyyy-MM-dd")); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -1984,7 +1980,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &myError, QS { if (!getValue(qry.value(_tableDaily.fieldTime), &date)) { - myError = "Missing fieldTime"; + errorStr = "Missing fieldTime"; return false; } @@ -1993,7 +1989,7 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &myError, QS varCode = _tableDaily.varcode[i].varCode; if (!getValue(qry.value(_tableDaily.varcode[i].varField), &value)) { - myError = "Missing VarField"; + errorStr = "Missing VarField"; } meteoVariable variable = getDailyVarEnum(varCode); @@ -2008,15 +2004,15 @@ bool Crit3DMeteoGridDbHandler::loadGridDailyDataFixedFields(QString &myError, QS } -bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &myError, QString meteoPoint, QDateTime firstDate, QDateTime lastDate) +bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &errorStr, QString meteoPoint, QDateTime firstDate, QDateTime lastDate) { - myError = ""; + errorStr = ""; QString tableH = _tableHourly.prefix + meteoPoint + _tableHourly.postFix; unsigned row, col; - if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) + if (! _meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id"; + errorStr = "Missing MeteoPoint id"; return false; } @@ -2025,7 +2021,7 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &myError, QString mete if (firstDate.date() > _lastHourlyDate || lastDate.date() < _firstHourlyDate) { - myError = "missing data"; + errorStr = "missing data"; return false; } @@ -2037,9 +2033,9 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &myError, QString mete .arg(tableH, _tableHourly.fieldTime, firstDate.toString("yyyy-MM-dd hh:mm"), lastDate.toString("yyyy-MM-dd hh:mm") ); - if( !qry.exec(statement) ) + if(! qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); } else { @@ -2051,13 +2047,13 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &myError, QString mete { if (! getValue(qry.value(_tableHourly.fieldTime), &date)) { - myError = "Missing fieldTime"; + errorStr = "Missing fieldTime"; return false; } if (! getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode"; + errorStr = "Missing VariableCode"; return false; } meteoVariable variable = getHourlyVarEnum(varCode); @@ -2065,7 +2061,7 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &myError, QString mete if (! _meteoGrid->meteoPointPointer(row,col)->setMeteoPointValueH(getCrit3DDate(date.date()), date.time().hour(), date.time().minute(), variable, value)) { - myError = "Error in setMeteoPointValueH"; + errorStr = "Wrong VariableCode: " + QString::number(varCode); return false; } } @@ -2076,13 +2072,13 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyData(QString &myError, QString mete } -bool Crit3DMeteoGridDbHandler::loadGridHourlyDataEnsemble(QString &myError, QString meteoPoint, int memberNr, QDateTime first, QDateTime last) +bool Crit3DMeteoGridDbHandler::loadGridHourlyDataEnsemble(QString &errorStr, QString meteoPoint, int memberNr, QDateTime first, QDateTime last) { - myError = ""; + errorStr = ""; if (!_meteoGrid->gridStructure().isEnsemble()) { - myError = "Grid structure has not ensemble field"; + errorStr = "Grid structure has not ensemble field"; return false; } @@ -2097,7 +2093,7 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataEnsemble(QString &myError, QStr if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id"; + errorStr = "Missing MeteoPoint id"; return false; } @@ -2105,11 +2101,11 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataEnsemble(QString &myError, QStr _meteoGrid->meteoPointPointer(row, col)->initializeObsDataH(1, numberOfDays, getCrit3DDate(first.date())); QString statement = QString("SELECT * FROM `%1` WHERE `%2` >= '%3' AND `%2` <= '%4' AND MemberNr = '%5' ORDER BY `%2`") - .arg(tableH).arg(_tableHourly.fieldTime).arg(first.toString("yyyy-MM-dd hh:mm")).arg(last.toString("yyyy-MM-dd hh:mm")).arg(memberNr); + .arg(tableH, _tableHourly.fieldTime).arg(first.toString("yyyy-MM-dd hh:mm")).arg(last.toString("yyyy-MM-dd hh:mm")).arg(memberNr); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); } else { @@ -2117,19 +2113,19 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataEnsemble(QString &myError, QStr { if (!getValue(qry.value(_tableHourly.fieldTime), &date)) { - myError = "Missing fieldTime"; + errorStr = "Missing fieldTime"; return false; } if (!getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode"; + errorStr = "Missing VariableCode"; return false; } if (!getValue(qry.value("Value"), &value)) { - myError = "Missing Value"; + errorStr = "Missing Value"; } meteoVariable variable = getHourlyVarEnum(varCode); @@ -2143,9 +2139,9 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataEnsemble(QString &myError, QStr } -bool Crit3DMeteoGridDbHandler::loadGridHourlyDataFixedFields(QString &myError, QString meteoPoint, QDateTime first, QDateTime last) +bool Crit3DMeteoGridDbHandler::loadGridHourlyDataFixedFields(QString &errorStr, QString meteoPoint, QDateTime first, QDateTime last) { - myError = ""; + errorStr = ""; QSqlQuery qry(_db); QString tableH = _tableHourly.prefix + meteoPoint + _tableHourly.postFix; @@ -2158,17 +2154,17 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataFixedFields(QString &myError, Q if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id"; + errorStr = "Missing MeteoPoint id"; return false; } int numberOfDays = first.date().daysTo(last.date()); _meteoGrid->meteoPointPointer(row, col)->initializeObsDataH(1, numberOfDays, getCrit3DDate(first.date())); - QString statement = QString("SELECT * FROM `%1` WHERE `%2` >= '%3' AND `%2`<= '%4' ORDER BY `%2`").arg(tableH).arg(_tableHourly.fieldTime).arg(first.toString("yyyy-MM-dd hh:mm")).arg(last.toString("yyyy-MM-dd hh:mm")); + QString statement = QString("SELECT * FROM `%1` WHERE `%2` >= '%3' AND `%2`<= '%4' ORDER BY `%2`").arg(tableH, _tableHourly.fieldTime).arg(first.toString("yyyy-MM-dd hh:mm")).arg(last.toString("yyyy-MM-dd hh:mm")); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); } else { @@ -2176,7 +2172,7 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataFixedFields(QString &myError, Q { if (!getValue(qry.value(_tableHourly.fieldTime), &date)) { - myError = "Missing fieldTime"; + errorStr = "Missing fieldTime"; return false; } @@ -2186,7 +2182,7 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataFixedFields(QString &myError, Q if (!getValue(qry.value(_tableHourly.varcode[i].varField), &value)) { - myError = "Missing fieldTime"; + errorStr = "Missing fieldTime"; } meteoVariable variable = getHourlyVarEnum(varCode); @@ -2202,14 +2198,14 @@ bool Crit3DMeteoGridDbHandler::loadGridHourlyDataFixedFields(QString &myError, Q } -bool Crit3DMeteoGridDbHandler::loadGridMonthlySingleDate(QString &myError, const QString &meteoPoint, const QDate &myDate) +bool Crit3DMeteoGridDbHandler::loadGridMonthlySingleDate(QString &errorStr, const QString &meteoPoint, const QDate &myDate) { - myError = ""; + errorStr = ""; unsigned row, col; if (! _meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id: " + meteoPoint; + errorStr = "Missing MeteoPoint id: " + meteoPoint; return false; } @@ -2227,7 +2223,7 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlySingleDate(QString &myError, const .arg(meteoPoint).arg(year).arg(month); if(! qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } @@ -2237,7 +2233,7 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlySingleDate(QString &myError, const { if (! getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode."; + errorStr = "Missing VariableCode."; return false; } meteoVariable variable = getMonthlyVarEnum(varCode); @@ -2252,9 +2248,9 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlySingleDate(QString &myError, const } -bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &myError, QString meteoPoint, QDate firstDate, QDate lastDate) +bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &errorStr, QString meteoPoint, QDate firstDate, QDate lastDate) { - myError = ""; + errorStr = ""; QString table = "MonthlyData"; // set day to 1 to better comparison @@ -2264,7 +2260,7 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &myError, QString met unsigned row, col; if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - myError = "Missing MeteoPoint id"; + errorStr = "Missing MeteoPoint id"; return false; } @@ -2283,7 +2279,7 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &myError, QString met QString statement = QString("SELECT * FROM `%1` WHERE `PragaYear` BETWEEN %2 AND %3 AND PointCode = '%4' ORDER BY `PragaYear`").arg(table).arg(firstDate.year()).arg(lastDate.year()).arg(meteoPoint); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -2292,13 +2288,13 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &myError, QString met { if (!getValue(qry.value("PragaYear"), &year)) { - myError = "Missing PragaYear"; + errorStr = "Missing PragaYear"; return false; } if (!getValue(qry.value("PragaMonth"), &month)) { - myError = "Missing PragaMonth"; + errorStr = "Missing PragaMonth"; return false; } @@ -2310,13 +2306,13 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &myError, QString met if (!getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode"; + errorStr = "Missing VariableCode"; return false; } if (!getValue(qry.value("Value"), &value)) { - myError = "Missing Value"; + errorStr = "Missing Value"; } meteoVariable variable = getMonthlyVarEnum(varCode); @@ -2330,9 +2326,9 @@ bool Crit3DMeteoGridDbHandler::loadGridMonthlyData(QString &myError, QString met } -bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate firstDate, QDate lastDate) +bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &errorStr, QDate firstDate, QDate lastDate) { - myError = ""; + errorStr = ""; QString table = "MonthlyData"; // set day to 1 to better comparison @@ -2366,7 +2362,7 @@ bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate fi QString statement = QString("SELECT * FROM `%1` WHERE `PragaYear` BETWEEN %2 AND %3 ORDER BY `PointCode`").arg(table).arg(firstDate.year()).arg(lastDate.year()); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } else @@ -2375,13 +2371,13 @@ bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate fi { if (! getValue(qry.value("PragaYear"), &year)) { - myError = "Missing PragaYear"; + errorStr = "Missing PragaYear"; return false; } if (! getValue(qry.value("PragaMonth"), &month)) { - myError = "Missing PragaMonth"; + errorStr = "Missing PragaMonth"; return false; } @@ -2393,7 +2389,7 @@ bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate fi if (! getValue(qry.value("PointCode"), &pointCode)) { - myError = "Missing PointCode"; + errorStr = "Missing PointCode"; return false; } @@ -2408,7 +2404,7 @@ bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate fi if (! getValue(qry.value("VariableCode"), &varCode)) { - myError = "Missing VariableCode: " + QString::number(varCode); + errorStr = "Missing VariableCode: " + QString::number(varCode); return false; } @@ -2420,12 +2416,12 @@ bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate fi if (! getValue(qry.value("Value"), &value)) { - myError = "Missing Value"; + errorStr = "Missing Value"; } if (! _meteoGrid->meteoPointPointer(row, col)->setMeteoPointValueM(getCrit3DDate(monthDate), variable, value)) { - myError = "Error in setMeteoPointValueM()"; + errorStr = "Error in setMeteoPointValueM()"; return false; } } @@ -2435,7 +2431,7 @@ bool Crit3DMeteoGridDbHandler::loadGridAllMonthlyData(QString &myError, QDate fi } -std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, QString meteoPoint, +std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *errorStr, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate* firstDateDB) { @@ -2447,14 +2443,14 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, int varCode = getDailyVarCode(variable); if (varCode == NODATA) { - *myError = "Variable not existing"; + *errorStr = "Variable not existing"; return dailyVarList; } unsigned row, col; if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - *myError = "Missing MeteoPoint id"; + *errorStr = "Missing MeteoPoint id"; return dailyVarList; } @@ -2462,10 +2458,10 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, if(! qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); if (!_db.isOpen()) { - qDebug() << "qry exec: db is not open: " << *myError; + qDebug() << "qry exec: db is not open: " << *errorStr; exit(EXIT_FAILURE); } else @@ -2477,10 +2473,10 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, // read first date if (!qry.first()) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); if (!_db.isOpen()) { - qDebug() << "qry.first: db is not open: " << *myError; + qDebug() << "qry.first: db is not open: " << *errorStr; exit(EXIT_FAILURE); } else @@ -2491,10 +2487,10 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, if (!getValue(qry.value(_tableDaily.fieldTime), firstDateDB)) { - *myError = "Missing first date"; + *errorStr = "Missing first date"; if (!_db.isOpen()) { - qDebug() << "qry.value: db is not open: " << *myError; + qDebug() << "qry.value: db is not open: " << *errorStr; exit(EXIT_FAILURE); } else @@ -2505,9 +2501,9 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, // read last date qry.last(); - if (!getValue(qry.value(_tableDaily.fieldTime), &lastDateDB)) + if (! getValue(qry.value(_tableDaily.fieldTime), &lastDateDB)) { - *myError = "Missing last date"; + *errorStr = "Missing last date"; return dailyVarList; } @@ -2535,7 +2531,8 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVar(QString *myError, return dailyVarList; } -std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *myError, frequencyType freq, meteoVariable variable, QString id, QDateTime myFirstTime, QDateTime myLastTime, std::vector &dateStr) + +std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *errorStr, frequencyType freq, meteoVariable variable, QString id, QDateTime myFirstTime, QDateTime myLastTime, std::vector &dateStr) { QString myDateStr; float value; @@ -2553,7 +2550,7 @@ std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *myError, idVar = getDailyVarCode(variable); if (idVar == NODATA) { - *myError = "Variable not existing"; + *errorStr = "Variable not existing"; return allDataVarList; } tableName = _tableDaily.prefix + id + _tableDaily.postFix; @@ -2567,25 +2564,25 @@ std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *myError, idVar = getHourlyVarCode(variable); if (idVar == NODATA) { - *myError = "Variable not existing"; + *errorStr = "Variable not existing"; return allDataVarList; } tableName = _tableHourly.prefix + id + _tableHourly.postFix; startDate = myFirstTime.date().toString("yyyy-MM-dd") + " " + myFirstTime.time().toString("hh:mm"); endDate = myLastTime.date().toString("yyyy-MM-dd") + " " + myLastTime.time().toString("hh:mm"); statement = QString( "SELECT * FROM `%1` WHERE VariableCode = '%2' AND `%3` >= '%4' AND `%3`<= '%5'") - .arg(tableName).arg(idVar).arg(_tableHourly.fieldTime).arg(startDate).arg(endDate); + .arg(tableName).arg(idVar).arg(_tableHourly.fieldTime, startDate, endDate); } else { - *myError = "Frequency should be daily or hourly"; + *errorStr = "Frequency should be daily or hourly"; return allDataVarList; } QDateTime dateTime; QDate date; if( !myQuery.exec(statement) ) { - *myError = myQuery.lastError().text(); + *errorStr = myQuery.lastError().text(); return allDataVarList; } else @@ -2596,7 +2593,7 @@ std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *myError, { if (! getValue(myQuery.value(_tableDaily.fieldTime), &date)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return allDataVarList; } myDateStr = date.toString("yyyy-MM-dd"); @@ -2605,7 +2602,7 @@ std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *myError, { if (! getValue(myQuery.value(_tableHourly.fieldTime), &dateTime)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return allDataVarList; } // LC dateTime.toString direttamente ritorna una stringa vuota nelle ore di passaggio all'ora legale @@ -2622,7 +2619,7 @@ std::vector Crit3DMeteoGridDbHandler::exportAllDataVar(QString *myError, } -std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString *myError, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate* firstDateDB) +std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString *errorStr, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate* firstDateDB) { QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPoint + _tableDaily.postFix; @@ -2638,7 +2635,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString if (varCode == NODATA) { - *myError = "Variable not existing"; + *errorStr = "Variable not existing"; return dailyVarList; } @@ -2654,7 +2651,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString QString statement = QString("SELECT `%1`, `%2` FROM `%3` WHERE `%1` >= '%4' AND `%1` <= '%5' ORDER BY `%1`").arg(_tableDaily.fieldTime).arg(varField).arg(tableD).arg(first.toString("yyyy-MM-dd")).arg(last.toString("yyyy-MM-dd")); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); } else { @@ -2665,13 +2662,13 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString { if (!getValue(qry.value(_tableDaily.fieldTime), firstDateDB)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return dailyVarList; } if (!getValue(qry.value(varField), &value)) { - *myError = "Missing Value"; + *errorStr = "Missing Value"; } dailyVarList.push_back(value); previousDate = *firstDateDB; @@ -2681,7 +2678,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString { if (!getValue(qry.value(_tableDaily.fieldTime), &date)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return dailyVarList; } @@ -2693,7 +2690,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString if (!getValue(qry.value(varField), &value)) { - *myError = "Missing Value"; + *errorStr = "Missing Value"; } dailyVarList.push_back(value); previousDate = date; @@ -2707,7 +2704,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridDailyVarFixedFields(QString } -std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *myError, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB) +std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *errorStr, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB) { QSqlQuery qry(_db); @@ -2727,20 +2724,20 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *myError, if (varCode == NODATA) { - *myError = "Variable not existing"; + *errorStr = "Variable not existing"; return hourlyVarList; } if (!_meteoGrid->findMeteoPointFromId(&row, &col, meteoPoint.toStdString()) ) { - *myError = "Missing MeteoPoint id"; + *errorStr = "Missing MeteoPoint id"; return hourlyVarList; } QString statement = QString("SELECT * FROM `%1` WHERE VariableCode = '%2' AND `%3` >= '%4' AND `%3` <= '%5' ORDER BY `%3`").arg(tableH).arg(varCode).arg(_tableHourly.fieldTime).arg(first.toString("yyyy-MM-dd hh:mm")).arg(last.toString("yyyy-MM-dd hh:mm")); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); } else { @@ -2751,13 +2748,13 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *myError, { if (!getValue(qry.value(_tableHourly.fieldTime), firstDateDB)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return hourlyVarList; } if (!getValue(qry.value("Value"), &value)) { - *myError = "Missing Value"; + *errorStr = "Missing Value"; } hourlyVarList.push_back(value); previousDateTime = *firstDateDB; @@ -2767,7 +2764,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *myError, { if (!getValue(qry.value(_tableHourly.fieldTime), &dateTime)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return hourlyVarList; } @@ -2779,7 +2776,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *myError, if (!getValue(qry.value("Value"), &value)) { - *myError = "Missing Value"; + *errorStr = "Missing Value"; } hourlyVarList.push_back(value); previousDateTime = dateTime; @@ -2794,7 +2791,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVar(QString *myError, } -std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QString *myError, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB) +std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QString *errorStr, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB) { QSqlQuery qry(_db); QString tableH = _tableHourly.prefix + meteoPoint + _tableHourly.postFix; @@ -2810,7 +2807,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QStrin if (varCode == NODATA) { - *myError = "Variable not existing"; + *errorStr = "Variable not existing"; return hourlyVarList; } @@ -2828,7 +2825,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QStrin QString statement = QString("SELECT `%1`, `%2` FROM `%3` WHERE `%1` >= '%4' AND `%1` <= '%5' ORDER BY `%1`").arg(_tableHourly.fieldTime).arg(varField).arg(tableH).arg(first.toString("yyyy-MM-dd hh:mm")).arg(last.toString("yyyy-MM-dd hh:mm")); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); } else { @@ -2839,13 +2836,13 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QStrin { if (!getValue(qry.value(_tableHourly.fieldTime), firstDateDB)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return hourlyVarList; } if (!getValue(qry.value(varField), &value)) { - *myError = "Missing Value"; + *errorStr = "Missing Value"; } hourlyVarList.push_back(value); previousDateTime = *firstDateDB; @@ -2855,7 +2852,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QStrin { if (!getValue(qry.value(_tableHourly.fieldTime), &dateTime)) { - *myError = "Missing fieldTime"; + *errorStr = "Missing fieldTime"; return hourlyVarList; } @@ -2867,7 +2864,7 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QStrin if (!getValue(qry.value(varField), &value)) { - *myError = "Missing Value"; + *errorStr = "Missing Value"; } hourlyVarList.push_back(value); previousDateTime = dateTime; @@ -2882,18 +2879,18 @@ std::vector Crit3DMeteoGridDbHandler::loadGridHourlyVarFixedFields(QStrin } -bool Crit3DMeteoGridDbHandler::saveCellGridDailyData(QString *myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, +bool Crit3DMeteoGridDbHandler::saveCellGridDailyData(QString *errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings) { QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPointID + _tableDaily.postFix; QString statement = QString("CREATE TABLE IF NOT EXISTS `%1`" - "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableD).arg(_tableDaily.fieldTime); + "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableD, _tableDaily.fieldTime); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -2918,7 +2915,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridDailyData(QString *myError, QString m if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -2928,7 +2925,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridDailyData(QString *myError, QString m // warning: delete all previous data -bool Crit3DMeteoGridDbHandler::deleteAndWriteCellGridDailyData(QString& myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, +bool Crit3DMeteoGridDbHandler::deleteAndWriteCellGridDailyData(QString& errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings) { QSqlQuery qry(_db); @@ -2937,10 +2934,10 @@ bool Crit3DMeteoGridDbHandler::deleteAndWriteCellGridDailyData(QString& myError, QString statement = QString("DROP TABLE `%1`").arg(tableD); qry.exec(statement); - statement = QString("CREATE TABLE `%1`(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableD).arg(_tableDaily.fieldTime); + statement = QString("CREATE TABLE `%1`(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableD, _tableDaily.fieldTime); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } @@ -2965,7 +2962,7 @@ bool Crit3DMeteoGridDbHandler::deleteAndWriteCellGridDailyData(QString& myError, statement = statement.left(statement.length() - 1); if( !qry.exec(statement) ) { - myError = qry.lastError().text(); + errorStr = qry.lastError().text(); return false; } @@ -2973,23 +2970,23 @@ bool Crit3DMeteoGridDbHandler::deleteAndWriteCellGridDailyData(QString& myError, } -bool Crit3DMeteoGridDbHandler::saveCellGridDailyDataEnsemble(QString *myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, +bool Crit3DMeteoGridDbHandler::saveCellGridDailyDataEnsemble(QString *errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, int memberNr, Crit3DMeteoSettings* meteoSettings) { QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPointID + _tableDaily.postFix; QString statement = QString("CREATE TABLE IF NOT EXISTS `%1`" - "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), MemberNr int(11), PRIMARY KEY(%2,VariableCode,MemberNr))").arg(tableD).arg(_tableDaily.fieldTime); + "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), MemberNr int(11), PRIMARY KEY(%2,VariableCode,MemberNr))").arg(tableD, _tableDaily.fieldTime); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else { - statement = QString(("REPLACE INTO `%1` (%2, VariableCode, Value, MemberNr) VALUES ")).arg(tableD).arg(_tableDaily.fieldTime); + statement = QString(("REPLACE INTO `%1` (%2, VariableCode, Value, MemberNr) VALUES ")).arg(tableD, _tableDaily.fieldTime); foreach (meteoVariable meteoVar, meteoVariableList) if (getVarFrequency(meteoVar) == daily) @@ -3010,7 +3007,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridDailyDataEnsemble(QString *myError, Q if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -3018,29 +3015,29 @@ bool Crit3DMeteoGridDbHandler::saveCellGridDailyDataEnsemble(QString *myError, Q return true; } -bool Crit3DMeteoGridDbHandler::saveListHourlyData(QString *myError, QString meteoPointID, QDateTime firstDateTime, meteoVariable meteoVar, QList values) +bool Crit3DMeteoGridDbHandler::saveListHourlyData(QString *errorStr, QString meteoPointID, QDateTime firstDateTime, meteoVariable meteoVar, QList values) { QSqlQuery qry(_db); QString tableH = _tableHourly.prefix + meteoPointID + _tableHourly.postFix; int varCode = getHourlyVarCode(meteoVar); QString statement = QString("CREATE TABLE IF NOT EXISTS `%1`" - "(%2 datetime, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableH).arg(_tableHourly.fieldTime); + "(%2 datetime, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableH, _tableHourly.fieldTime); qry.exec(statement); int nHours = values.size(); QDateTime last = firstDateTime.addSecs(3600*(nHours-1)); statement = QString("DELETE FROM `%1` WHERE %2 BETWEEN CAST('%3' AS DATETIME) AND CAST('%4' AS DATETIME) AND VariableCode = '%5'") - .arg(tableH).arg(_tableHourly.fieldTime).arg(firstDateTime.toString("yyyy-MM-dd hh:mm:00")).arg(last.toString("yyyy-MM-dd hh:mm:00")).arg(varCode); + .arg(tableH, _tableHourly.fieldTime).arg(firstDateTime.toString("yyyy-MM-dd hh:mm:00")).arg(last.toString("yyyy-MM-dd hh:mm:00")).arg(varCode); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else { - statement = QString(("INSERT INTO `%1` (%2, VariableCode, Value) VALUES ")).arg(tableH).arg(_tableHourly.fieldTime); + statement = QString(("INSERT INTO `%1` (%2, VariableCode, Value) VALUES ")).arg(tableH, _tableHourly.fieldTime); for (int i = 0; i values, bool reverseOrder) +bool Crit3DMeteoGridDbHandler::saveListDailyData(QString *errorStr, QString meteoPointID, QDate firstDate, meteoVariable meteoVar, QList values, bool reverseOrder) { QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPointID + _tableDaily.postFix; int varCode = getDailyVarCode(meteoVar); QString statement = QString("CREATE TABLE IF NOT EXISTS `%1`" - "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableD).arg(_tableDaily.fieldTime); + "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(%2,VariableCode))").arg(tableD, _tableDaily.fieldTime); qry.exec(statement); int nDays = values.size(); QDate lastDate = firstDate.addDays(nDays-1); statement = QString("DELETE FROM `%1` WHERE %2 BETWEEN CAST('%3' AS DATE) AND CAST('%4' AS DATE) AND VariableCode = '%5'") - .arg(tableD).arg(_tableDaily.fieldTime).arg(firstDate.toString("yyyy-MM-dd")).arg(lastDate.toString("yyyy-MM-dd")).arg(varCode); + .arg(tableD, _tableDaily.fieldTime).arg(firstDate.toString("yyyy-MM-dd")).arg(lastDate.toString("yyyy-MM-dd")).arg(varCode); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else { - statement = QString(("INSERT INTO `%1` (%2, VariableCode, Value) VALUES ")).arg(tableD).arg(_tableDaily.fieldTime); + statement = QString(("INSERT INTO `%1` (%2, VariableCode, Value) VALUES ")).arg(tableD, _tableDaily.fieldTime); for (int i = 0; i values) + +bool Crit3DMeteoGridDbHandler::saveListDailyDataEnsemble(QString *errorStr, QString meteoPointID, QDate date, meteoVariable meteoVar, QList values) { QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPointID + _tableDaily.postFix; int varCode = getDailyVarCode(meteoVar); QString statement = QString("CREATE TABLE IF NOT EXISTS `%1`" - "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), MemberNr int(11), PRIMARY KEY(%2,VariableCode,MemberNr))").arg(tableD).arg(_tableDaily.fieldTime); + "(%2 date, VariableCode tinyint(3) UNSIGNED, Value float(6,1), MemberNr int(11), PRIMARY KEY(%2,VariableCode,MemberNr))").arg(tableD, _tableDaily.fieldTime); qry.exec(statement); statement = QString("DELETE FROM `%1` WHERE %2 = DATE('%3') AND VariableCode = '%4'") - .arg(tableD).arg(_tableDaily.fieldTime).arg(date.toString("yyyy-MM-dd")).arg(varCode); - if( !qry.exec(statement) ) + .arg(tableD, _tableDaily.fieldTime, date.toString("yyyy-MM-dd")).arg(varCode); + if(! qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else { - statement = QString(("INSERT INTO `%1` (%2, VariableCode, Value, MemberNr) VALUES ")).arg(tableD).arg(_tableDaily.fieldTime); - for (int i = 0; i meteoVariableList) { QSqlQuery qry(_db); @@ -3396,7 +3397,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridMonthlyData(QString *myError, QString if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3426,7 +3427,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridMonthlyData(QString *myError, QString if( ! qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -3434,7 +3435,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridMonthlyData(QString *myError, QString return true; } -bool Crit3DMeteoGridDbHandler::saveGridData(QString *myError, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings) +bool Crit3DMeteoGridDbHandler::saveGridData(QString *errorStr, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings) { std::string id; meteoVariable var; @@ -3457,13 +3458,13 @@ bool Crit3DMeteoGridDbHandler::saveGridData(QString *myError, QDateTime firstTim { if (! gridStructure().isFixedFields()) { - if (isHourly) saveCellGridHourlyData(myError, QString::fromStdString(id), row, col, firstTime, lastTime, meteoVariableList); - if (isDaily) saveCellGridDailyData(myError, QString::fromStdString(id), row, col, firstTime.date(), lastDate, meteoVariableList, meteoSettings); + if (isHourly) saveCellGridHourlyData(errorStr, QString::fromStdString(id), row, col, firstTime, lastTime, meteoVariableList); + if (isDaily) saveCellGridDailyData(errorStr, QString::fromStdString(id), row, col, firstTime.date(), lastDate, meteoVariableList, meteoSettings); } else { - if (isHourly) saveCellGridHourlyDataFF(myError, QString::fromStdString(id), row, col, firstTime, lastTime); - if (isDaily) saveCellGridDailyDataFF(myError, QString::fromStdString(id), row, col, firstTime.date(), lastDate, meteoSettings); + if (isHourly) saveCellGridHourlyDataFF(errorStr, QString::fromStdString(id), row, col, firstTime, lastTime); + if (isDaily) saveCellGridDailyDataFF(errorStr, QString::fromStdString(id), row, col, firstTime.date(), lastDate, meteoSettings); } } @@ -3471,7 +3472,7 @@ bool Crit3DMeteoGridDbHandler::saveGridData(QString *myError, QDateTime firstTim } -bool Crit3DMeteoGridDbHandler::saveGridHourlyData(QString *myError, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList) +bool Crit3DMeteoGridDbHandler::saveGridHourlyData(QString *errorStr, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList) { std::string id; @@ -3483,11 +3484,11 @@ bool Crit3DMeteoGridDbHandler::saveGridHourlyData(QString *myError, QDateTime fi { if (!gridStructure().isFixedFields()) { - saveCellGridHourlyData(myError, QString::fromStdString(id), row, col, firstDate, lastDate, meteoVariableList); + saveCellGridHourlyData(errorStr, QString::fromStdString(id), row, col, firstDate, lastDate, meteoVariableList); } else { - saveCellGridHourlyDataFF(myError, QString::fromStdString(id), row, col, firstDate, lastDate); + saveCellGridHourlyDataFF(errorStr, QString::fromStdString(id), row, col, firstDate, lastDate); } } } @@ -3496,7 +3497,7 @@ bool Crit3DMeteoGridDbHandler::saveGridHourlyData(QString *myError, QDateTime fi return true; } -bool Crit3DMeteoGridDbHandler::saveGridDailyData(QString *myError, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings) +bool Crit3DMeteoGridDbHandler::saveGridDailyData(QString *errorStr, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings) { std::string id; @@ -3508,11 +3509,11 @@ bool Crit3DMeteoGridDbHandler::saveGridDailyData(QString *myError, QDateTime fir { if (! gridStructure().isFixedFields()) { - saveCellGridDailyData(myError, QString::fromStdString(id), row, col, firstDate.date(), lastDate.date(), meteoVariableList, meteoSettings); + saveCellGridDailyData(errorStr, QString::fromStdString(id), row, col, firstDate.date(), lastDate.date(), meteoVariableList, meteoSettings); } else { - saveCellGridDailyDataFF(myError, QString::fromStdString(id), row, col, firstDate.date(), lastDate.date(), meteoSettings); + saveCellGridDailyDataFF(errorStr, QString::fromStdString(id), row, col, firstDate.date(), lastDate.date(), meteoSettings); } } } @@ -3521,7 +3522,7 @@ bool Crit3DMeteoGridDbHandler::saveGridDailyData(QString *myError, QDateTime fir return true; } -bool Crit3DMeteoGridDbHandler::saveCellGridHourlyData(QString *myError, QString meteoPointID, int row, int col, +bool Crit3DMeteoGridDbHandler::saveCellGridHourlyData(QString *errorStr, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList) { QSqlQuery qry(_db); @@ -3529,11 +3530,11 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyData(QString *myError, QString QString statement = QString("CREATE TABLE IF NOT EXISTS `%1` " - "(`%2` datetime, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(`%2`,VariableCode))").arg(tableH).arg(_tableHourly.fieldTime); + "(`%2` datetime, VariableCode tinyint(3) UNSIGNED, Value float(6,1), PRIMARY KEY(`%2`,VariableCode))").arg(tableH, _tableHourly.fieldTime); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3558,7 +3559,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyData(QString *myError, QString if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -3566,7 +3567,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyData(QString *myError, QString return true; } -bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataEnsemble(QString *myError, QString meteoPointID, int row, int col, +bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataEnsemble(QString *errorStr, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList, int memberNr) { QSqlQuery qry(_db); @@ -3579,7 +3580,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataEnsemble(QString *myError, if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3604,7 +3605,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataEnsemble(QString *myError, if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -3612,7 +3613,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataEnsemble(QString *myError, return true; } -bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataFF(QString *myError, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime) +bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataFF(QString *errorStr, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime) { QSqlQuery qry(_db); QString tableH = _tableHourly.prefix + meteoPointID + _tableHourly.postFix; @@ -3631,7 +3632,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataFF(QString *myError, QStrin if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3659,7 +3660,7 @@ bool Crit3DMeteoGridDbHandler::saveCellGridHourlyDataFF(QString *myError, QStrin if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -3798,6 +3799,7 @@ QDate Crit3DMeteoGridDbHandler::getFirstDailyDate() const return _firstDailyDate; } + QDate Crit3DMeteoGridDbHandler::getLastDailyDate() const { if (_lastDailyDate.year() == 1800) @@ -3807,6 +3809,7 @@ QDate Crit3DMeteoGridDbHandler::getLastDailyDate() const return _lastDailyDate; } + QDate Crit3DMeteoGridDbHandler::getFirstHourlyDate() const { if (_firstHourlyDate.year() == 1800) @@ -3816,6 +3819,7 @@ QDate Crit3DMeteoGridDbHandler::getFirstHourlyDate() const return _firstHourlyDate; } + QDate Crit3DMeteoGridDbHandler::getLastHourlyDate() const { if (_lastHourlyDate.year() == 1800) @@ -3825,6 +3829,7 @@ QDate Crit3DMeteoGridDbHandler::getLastHourlyDate() const return _lastHourlyDate; } + QDate Crit3DMeteoGridDbHandler::getFirstMonthlytDate() const { if (_firstMonthlyDate.year() == 1800) @@ -3834,6 +3839,7 @@ QDate Crit3DMeteoGridDbHandler::getFirstMonthlytDate() const return _firstMonthlyDate; } + QDate Crit3DMeteoGridDbHandler::getLastMonthlyDate() const { if (_lastMonthlyDate.year() == 1800) @@ -3843,14 +3849,15 @@ QDate Crit3DMeteoGridDbHandler::getLastMonthlyDate() const return _lastMonthlyDate; } -bool Crit3DMeteoGridDbHandler::idDailyList(QString *myError, QList* idMeteoList) + +bool Crit3DMeteoGridDbHandler::idDailyList(QString *errorStr, QList* idMeteoList) { QSqlQuery qry(_db); QString statement = QString("SHOW TABLES LIKE '%1%%2'").arg(_tableDaily.prefix, _tableDaily.postFix); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3869,10 +3876,12 @@ bool Crit3DMeteoGridDbHandler::idDailyList(QString *myError, QList* idM idMeteoList->append(tableName); } } + return true; } -bool Crit3DMeteoGridDbHandler::getYearList(QString *myError, QString meteoPoint, QList* yearList) + +bool Crit3DMeteoGridDbHandler::getYearList(QString *errorStr, QString meteoPoint, QList* yearList) { QSqlQuery qry(_db); QString tableD = _tableDaily.prefix + meteoPoint + _tableDaily.postFix; @@ -3880,7 +3889,7 @@ bool Crit3DMeteoGridDbHandler::getYearList(QString *myError, QString meteoPoint, QString statement = QString("SELECT DISTINCT DATE_FORMAT(`%1`,'%Y') as Year FROM `%2` ORDER BY Year").arg(_tableDaily.fieldTime, tableD); if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3899,7 +3908,7 @@ bool Crit3DMeteoGridDbHandler::getYearList(QString *myError, QString meteoPoint, return true; } -bool Crit3DMeteoGridDbHandler::saveLogProcedures(QString *myError, QString nameProc, QDate date) +bool Crit3DMeteoGridDbHandler::saveLogProcedures(QString *errorStr, QString nameProc, QDate date) { QSqlQuery qry(_db); QString table = "log_procedures"; @@ -3909,7 +3918,7 @@ bool Crit3DMeteoGridDbHandler::saveLogProcedures(QString *myError, QString nameP if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } else @@ -3918,7 +3927,7 @@ bool Crit3DMeteoGridDbHandler::saveLogProcedures(QString *myError, QString nameP if( !qry.exec(statement) ) { - *myError = qry.lastError().text(); + *errorStr = qry.lastError().text(); return false; } } @@ -3927,16 +3936,74 @@ bool Crit3DMeteoGridDbHandler::saveLogProcedures(QString *myError, QString nameP } + +bool Crit3DMeteoGridDbHandler::saveDailyDataCsv(const QString &csvFileName, const QList &variableList, + const QDate &firstDate, const QDate &lastDate, + unsigned row, unsigned col, QString &errorStr) +{ + // create csv file + QFile outputFile(csvFileName); + bool isOk = outputFile.open(QIODevice::WriteOnly | QFile::Truncate); + if (! isOk) + { + errorStr = "Open CSV failed: " + csvFileName; + return false; + } + + // write header + QTextStream outStream(&outputFile); + outStream << "Date"; + for (int i = 0; i < variableList.size(); i++) + { + if (variableList[i] != noMeteoVar) + { + std::string varName = getMeteoVarName(variableList[i]); + std::string unit = getUnitFromVariable(variableList[i]); + QString VarString = QString::fromStdString(varName + " (" + unit + ")"); + outStream << "," + VarString; + } + } + outStream << "\n"; + + // write data + QDate currentDate = firstDate; + while (currentDate <= lastDate) + { + outStream << currentDate.toString("yyyy-MM-dd"); + + for (int i = 0; i < variableList.size(); i++) + { + if (variableList[i] != noMeteoVar) + { + float value = _meteoGrid->meteoPointPointer(row, col)->getMeteoPointValueD(getCrit3DDate(currentDate), variableList[i]); + QString valueString = ""; + if (value != NODATA) + valueString = QString::number(value); + + outStream << "," << valueString; + } + } + outStream << "\n"; + + currentDate = currentDate.addDays(1); + } + + outputFile.close(); + return true; +} + + /*! * \brief ExportDailyDataCsv * export gridded daily meteo data to csv files * \param variableList list of meteo variables - * \param idListFileName text file of cells id list by columns - if idListFileName is empty save ALL cells + * \param idListFileName text file of cells id list by columns - default (empty): ALL cells * \param outputPath path for output files * \return true on success, false otherwise */ -bool Crit3DMeteoGridDbHandler::exportDailyDataCsv(QString &errorStr, QList variableList, - QDate firstDate, QDate lastDate, QString idListFileName, QString outputPath) +bool Crit3DMeteoGridDbHandler::exportDailyDataCsv(const QList &variableList, const QDate &firstDate, + const QDate &lastDate, const QString &idListFileName, + QString &outputPath, QString &errorStr) { errorStr = ""; @@ -3985,74 +4052,52 @@ bool Crit3DMeteoGridDbHandler::exportDailyDataCsv(QString &errorStr, QListmeteoPoints()[row][col]->id); - if (! isList || idList.contains(id)) + if (idList.contains(id) || (! isList && meteoGrid()->meteoPoints()[row][col]->active)) { // read data - bool isOk; - if (gridStructure().isFixedFields()) - { - isOk = loadGridDailyDataFixedFields(errorStr, id, firstDate, lastDate); - } - else - { - isOk = loadGridDailyData(errorStr, id, firstDate, lastDate); - } - if (! isOk) + if (gridStructure().isEnsemble()) { - std::cout << "Error in reading cell id: " << id.toStdString() << "\n"; - continue; - } + for (int i = 1; i <= gridStructure().nrMembers(); i++) + { + if (loadGridDailyDataEnsemble(errorStr, id, i, firstDate, lastDate)) + { + QString csvFileName = outputPath + "/" + id + "_" + QString::number(i) + ".csv"; - // create csv file - QString csvFileName = outputPath + "/" + id + ".csv"; - QFile outputFile(csvFileName); - isOk = outputFile.open(QIODevice::WriteOnly | QFile::Truncate); - if (! isOk) - { - std::cout << "Open CSV failed: " << csvFileName.toStdString() << "\n"; - continue; + if (! saveDailyDataCsv(csvFileName, variableList, firstDate, lastDate, row, col, errorStr)) + { + std::cout << errorStr.toStdString(); + } + } + else + { + std::cout << errorStr.toStdString(); + } + } } - - // write header - QTextStream out(&outputFile); - out << "Date"; - for (int i = 0; i < variableList.size(); i++) + else { - if (variableList[i] != noMeteoVar) + bool isOk; + if (gridStructure().isFixedFields()) { - std::string varName = getMeteoVarName(variableList[i]); - std::string unit = getUnitFromVariable(variableList[i]); - QString VarString = QString::fromStdString(varName + " (" + unit + ")"); - out << "," + VarString; + isOk = loadGridDailyDataFixedFields(errorStr, id, firstDate, lastDate); } - } - out << "\n"; - - // write data - QDate currentDate = firstDate; - while (currentDate <= lastDate) - { - Crit3DDate myDate = getCrit3DDate(currentDate); - out << currentDate.toString("yyyy-MM-dd"); - - for (int i = 0; i < variableList.size(); i++) + else { - if (variableList[i] != noMeteoVar) - { - float value = _meteoGrid->meteoPointPointer(row,col)->getMeteoPointValueD(myDate, variableList[i]); - QString valueString = ""; - if (value != NODATA) - valueString = QString::number(value); + isOk = loadGridDailyData(errorStr, id, firstDate, lastDate); + } - out << "," << valueString; - } + if (! isOk) + { + std::cout << "Error in reading cell id: " << id.toStdString() << "\n"; + continue; } - out << "\n"; - currentDate = currentDate.addDays(1); + QString csvFileName = outputPath + "/" + id + ".csv"; + if (! saveDailyDataCsv(csvFileName, variableList, firstDate, lastDate, row, col, errorStr)) + { + std::cout << errorStr.toStdString(); + } } - - outputFile.close(); } } } @@ -4081,7 +4126,7 @@ bool Crit3DMeteoGridDbHandler::MeteoGridToRasterFlt(double cellSize, const gis:: { myGrid.getXY(row, col, utmx, utmy); gis::getLatLonFromUtm(gisSettings, utmx, utmy, &lat, &lon); - gis::getGridRowColFromXY (latlonHeader, lon, lat, &dataGridRow, &dataGridCol); + gis::getGridRowColFromLonLat (latlonHeader, lon, lat, &dataGridRow, &dataGridCol); if (dataGridRow < 0 || dataGridRow >= latlonHeader.nrRows || dataGridCol < 0 || dataGridCol >= latlonHeader.nrCols) { myValue = NODATA; @@ -4105,83 +4150,3 @@ bool Crit3DMeteoGridDbHandler::MeteoGridToRasterFlt(double cellSize, const gis:: return true; } - -QDate Crit3DMeteoGridDbHandler::firstDate() const -{ - return _firstDate; -} - -void Crit3DMeteoGridDbHandler::setFirstDate(const QDate &firstDate) -{ - _firstDate = firstDate; -} - -QDate Crit3DMeteoGridDbHandler::lastDate() const -{ - return _lastDate; -} - -void Crit3DMeteoGridDbHandler::setLastDate(const QDate &lastDate) -{ - _lastDate = lastDate; -} - -Crit3DMeteoGrid *Crit3DMeteoGridDbHandler::meteoGrid() const -{ - return _meteoGrid; -} - -void Crit3DMeteoGridDbHandler::setMeteoGrid(Crit3DMeteoGrid *meteoGrid) -{ - _meteoGrid = meteoGrid; -} - -QSqlDatabase Crit3DMeteoGridDbHandler::db() const -{ - return _db; -} - -void Crit3DMeteoGridDbHandler::setDb(const QSqlDatabase &db) -{ - _db = db; -} - -QString Crit3DMeteoGridDbHandler::fileName() const -{ - return _fileName; -} - -TXMLConnection Crit3DMeteoGridDbHandler::connection() const -{ - return _connection; -} - -Crit3DMeteoGridStructure Crit3DMeteoGridDbHandler::gridStructure() const -{ - return _gridStructure; -} - -TXMLTable Crit3DMeteoGridDbHandler::tableDaily() const -{ - return _tableDaily; -} - -TXMLTable Crit3DMeteoGridDbHandler::tableHourly() const -{ - return _tableHourly; -} - -TXMLTable Crit3DMeteoGridDbHandler::tableMonthly() const -{ - return _tableMonthly; -} - -QString Crit3DMeteoGridDbHandler::tableDailyModel() const -{ - return _tableDailyModel; -} - -QString Crit3DMeteoGridDbHandler::tableHourlyModel() const -{ - return _tableHourlyModel; -} diff --git a/agrolib/dbMeteoGrid/dbMeteoGrid.h b/agrolib/dbMeteoGrid/dbMeteoGrid.h index 0d72ea8c..4dca06f0 100644 --- a/agrolib/dbMeteoGrid/dbMeteoGrid.h +++ b/agrolib/dbMeteoGrid/dbMeteoGrid.h @@ -31,7 +31,6 @@ QString password; }; - struct TXMLvar { QString varField; @@ -58,35 +57,41 @@ Crit3DMeteoGridDbHandler(); ~Crit3DMeteoGridDbHandler(); - bool openDatabase(QString *myError); - bool openDatabase(QString *myError, QString connectionName); - bool newDatabase(QString *myError); - bool newDatabase(QString *myError, QString connectionName); - bool deleteDatabase(QString *myError); + QString fileName() const { return _fileName; } + TXMLConnection connection() const { return _connection; } + + QSqlDatabase db() const { return _db; } + void setDb(const QSqlDatabase &db) { _db = db; } + + QDate firstDate() const { return _firstDate; } + QDate lastDate() const { return _lastDate; } + + void setFirstDate(const QDate &firstDate) { _firstDate = firstDate; } + void setLastDate(const QDate &lastDate) { _lastDate = lastDate; } + + Crit3DMeteoGridStructure gridStructure() const { return _gridStructure; } + + Crit3DMeteoGrid *meteoGrid() const { return _meteoGrid; } + void setMeteoGrid(Crit3DMeteoGrid *meteoGrid) { _meteoGrid = meteoGrid; } + + TXMLTable tableHourly() const { return _tableHourly; } + TXMLTable tableDaily() const { return _tableDaily; } + TXMLTable tableMonthly() const { return _tableMonthly; } + + QString tableDailyModel() const { return _tableDailyModel; } + QString tableHourlyModel() const { return _tableHourlyModel; } + + bool openDatabase(QString *errorStr); + bool openDatabase(QString *errorStr, QString connectionName); + bool newDatabase(QString *errorStr); + bool newDatabase(QString *errorStr, QString connectionName); + bool deleteDatabase(QString *errorStr); void closeDatabase(); bool parseXMLFile(QString xmlFileName, QDomDocument* xmlDoc, QString *error); - bool checkXML(QString *myError); - bool parseXMLGrid(QString xmlFileName, QString *myError); + bool checkXML(QString *errorStr); + bool parseXMLGrid(QString xmlFileName, QString *errorStr); void initMapMySqlVarType(); - QSqlDatabase db() const; - QString fileName() const; - TXMLConnection connection() const; - Crit3DMeteoGridStructure gridStructure() const; - Crit3DMeteoGrid *meteoGrid() const; - QDate firstDate() const; - QDate lastDate() const; - TXMLTable tableDaily() const; - TXMLTable tableHourly() const; - TXMLTable tableMonthly() const; - QString tableDailyModel() const; - QString tableHourlyModel() const; - - void setMeteoGrid(Crit3DMeteoGrid *meteoGrid); - void setDb(const QSqlDatabase &db); - void setFirstDate(const QDate &firstDate); - void setLastDate(const QDate &lastDate); - int getDailyVarCode(meteoVariable meteoGridDailyVar); QString getDailyVarField(meteoVariable meteoGridDailyVar); meteoVariable getDailyVarEnum(int varCode); @@ -106,63 +111,67 @@ std::string getHourlyPragaName(meteoVariable meteoVar); std::string getMonthlyPragaName(meteoVariable meteoVar); - bool loadCellProperties(QString *myError); - bool newCellProperties(QString *myError); - bool writeCellProperties(QString *myError, int nRow, int nCol); - bool loadIdMeteoProperties(QString *myError, QString idMeteo); - bool updateMeteoGridDate(QString &myError); - - bool loadGridDailyData(QString &myError, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate); - bool loadGridDailyDataFixedFields(QString &myError, QString meteoPoint, QDate first, QDate last); - bool loadGridDailyDataEnsemble(QString &myError, QString meteoPoint, int memberNr, QDate first, QDate last); - bool loadGridDailyMeteoPrec(QString &myError, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate); - bool loadGridHourlyData(QString &myError, QString meteoPoint, QDateTime firstDate, QDateTime lastDate); - bool loadGridHourlyDataFixedFields(QString &myError, QString meteoPoint, QDateTime first, QDateTime last); - bool loadGridHourlyDataEnsemble(QString &myError, QString meteoPoint, int memberNr, QDateTime first, QDateTime last); - bool loadGridMonthlyData(QString &myError, QString meteoPoint, QDate firstDate, QDate lastDate); - bool loadGridAllMonthlyData(QString &myError, QDate firstDate, QDate lastDate); - bool loadGridMonthlySingleDate(QString &myError, const QString &meteoPoint, const QDate &myDate); - - std::vector loadGridDailyVar(QString *myError, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate *firstDateDB); - std::vector loadGridDailyVarFixedFields(QString *myError, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate* firstDateDB); - std::vector loadGridHourlyVar(QString *myError, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB); - std::vector loadGridHourlyVarFixedFields(QString *myError, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB); - std::vector exportAllDataVar(QString *myError, frequencyType freq, meteoVariable variable, QString id, QDateTime myFirstTime, QDateTime myLastTime, std::vector &dateStr); - bool getYearList(QString *myError, QString meteoPoint, QList* yearList); - bool idDailyList(QString *myError, QList* idMeteoList); - - bool saveGridData(QString *myError, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList, Crit3DMeteoSettings *meteoSettings); - bool saveGridHourlyData(QString *myError, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList); - bool saveGridDailyData(QString *myError, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList, Crit3DMeteoSettings *meteoSettings); - bool deleteAndWriteCellGridDailyData(QString& myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, + bool loadCellProperties(QString *errorStr); + bool newCellProperties(QString *errorStr); + bool writeCellProperties(QString *errorStr, int nRow, int nCol); + bool loadIdMeteoProperties(QString *errorStr, QString idMeteo); + bool updateMeteoGridDate(QString &errorStr); + + bool loadGridDailyData(QString &errorStr, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate); + bool loadGridDailyDataFixedFields(QString &errorStr, QString meteoPoint, QDate first, QDate last); + bool loadGridDailyDataEnsemble(QString &errorStr, QString meteoPoint, int memberNr, QDate first, QDate last); + bool loadGridDailyMeteoPrec(QString &errorStr, const QString &meteoPointId, const QDate &firstDate, const QDate &lastDate); + bool loadGridHourlyData(QString &errorStr, QString meteoPoint, QDateTime firstDate, QDateTime lastDate); + bool loadGridHourlyDataFixedFields(QString &errorStr, QString meteoPoint, QDateTime first, QDateTime last); + bool loadGridHourlyDataEnsemble(QString &errorStr, QString meteoPoint, int memberNr, QDateTime first, QDateTime last); + bool loadGridMonthlyData(QString &errorStr, QString meteoPoint, QDate firstDate, QDate lastDate); + bool loadGridAllMonthlyData(QString &errorStr, QDate firstDate, QDate lastDate); + bool loadGridMonthlySingleDate(QString &errorStr, const QString &meteoPoint, const QDate &myDate); + + std::vector loadGridDailyVar(QString *errorStr, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate *firstDateDB); + std::vector loadGridDailyVarFixedFields(QString *errorStr, QString meteoPoint, meteoVariable variable, QDate first, QDate last, QDate* firstDateDB); + std::vector loadGridHourlyVar(QString *errorStr, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB); + std::vector loadGridHourlyVarFixedFields(QString *errorStr, QString meteoPoint, meteoVariable variable, QDateTime first, QDateTime last, QDateTime* firstDateDB); + std::vector exportAllDataVar(QString *errorStr, frequencyType freq, meteoVariable variable, QString id, QDateTime myFirstTime, QDateTime myLastTime, std::vector &dateStr); + bool getYearList(QString *errorStr, QString meteoPoint, QList* yearList); + bool idDailyList(QString *errorStr, QList* idMeteoList); + + bool saveGridData(QString *errorStr, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList, Crit3DMeteoSettings *meteoSettings); + bool saveGridHourlyData(QString *errorStr, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList); + bool saveGridDailyData(QString *errorStr, QDateTime firstDate, QDateTime lastDate, QList meteoVariableList, Crit3DMeteoSettings *meteoSettings); + bool deleteAndWriteCellGridDailyData(QString& errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, Crit3DMeteoSettings* meteoSettings); - bool saveCellGridDailyData(QString *myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, Crit3DMeteoSettings *meteoSettings); - bool saveCellGridDailyDataFF(QString *myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, Crit3DMeteoSettings *meteoSettings); - bool saveCellGridDailyDataEnsemble(QString *myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, + bool saveCellGridDailyData(QString *errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, Crit3DMeteoSettings *meteoSettings); + bool saveCellGridDailyDataFF(QString *errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, Crit3DMeteoSettings *meteoSettings); + bool saveCellGridDailyDataEnsemble(QString *errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList, int memberNr, Crit3DMeteoSettings *meteoSettings); - bool saveCellGridMonthlyData(QString *myError, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, + bool saveCellGridMonthlyData(QString *errorStr, QString meteoPointID, int row, int col, QDate firstDate, QDate lastDate, QList meteoVariableList); - bool saveListDailyDataEnsemble(QString *myError, QString meteoPointID, QDate date, meteoVariable meteoVar, QList values); - bool saveListDailyData(QString *myError, QString meteoPointID, QDate firstDate, meteoVariable meteoVar, QList values, bool reverseOrder); - bool cleanDailyOldData(QString *myError, QDate date); - bool saveListHourlyData(QString *myError, QString meteoPointID, QDateTime firstDateTime, meteoVariable meteoVar, QList values); - bool saveCellCurrentGridDaily(QString *myError, QString meteoPointID, QDate date, int varCode, float value); + bool saveListDailyDataEnsemble(QString *errorStr, QString meteoPointID, QDate date, meteoVariable meteoVar, QList values); + bool saveListDailyData(QString *errorStr, QString meteoPointID, QDate firstDate, meteoVariable meteoVar, QList values, bool reverseOrder); + bool cleanDailyOldData(QString *errorStr, QDate date); + bool saveListHourlyData(QString *errorStr, QString meteoPointID, QDateTime firstDateTime, meteoVariable meteoVar, QList values); + bool saveCellCurrentGridDaily(QString *errorStr, QString meteoPointID, QDate date, int varCode, float value); bool saveCellCurrentGridDailyList(QString meteoPointID, QList listEntries, QString &errorStr); bool saveCellCurrentGridHourlyList(QString meteoPointID, QList listEntries, QString &errorStr); bool saveCellCurrentGridDailyFF(QString &errorStr, QString meteoPointID, QDate date, QString varPragaName, float value); - bool saveCellGridHourlyData(QString *myError, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList); - bool saveCellGridHourlyDataFF(QString *myError, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime); - bool saveCellGridHourlyDataEnsemble(QString *myError, QString meteoPointID, int row, int col, + bool saveCellGridHourlyData(QString *errorStr, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList); + bool saveCellGridHourlyDataFF(QString *errorStr, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime); + bool saveCellGridHourlyDataEnsemble(QString *errorStr, QString meteoPointID, int row, int col, QDateTime firstTime, QDateTime lastTime, QList meteoVariableList, int memberNr); bool saveCellCurrentGridHourly(QString& errorStr, QString meteoPointID, QDateTime dateTime, int varCode, float value); bool saveCellCurrentGridHourlyFF(QString &errorStr, QString meteoPointID, QDateTime dateTime, QString varPragaName, float value); - bool activeAllCells(QString *myError); - bool setActiveStateCellsInList(QString *myError, QList idList, bool activeState); + bool activeAllCells(QString *errorStr); + bool setActiveStateCellsInList(QString *errorStr, QList idList, bool activeState); + + bool saveDailyDataCsv(const QString &csvFileName, const QList &variableList, + const QDate &firstDate, const QDate &lastDate, unsigned row, unsigned col, QString &errorStr); + + bool exportDailyDataCsv(const QList &variableList, const QDate &firstDate, + const QDate &lastDate, const QString &idListFileName, QString &outputPath, QString &errorStr); - bool exportDailyDataCsv(QString &errorStr, QList variableList, - QDate firstDate, QDate lastDate, QString idListFileName, QString outputPath); bool MeteoGridToRasterFlt(double cellSize, const gis::Crit3DGisSettings &gisSettings, gis::Crit3DRasterGrid& myGrid); QDate getFirstDailyDate() const; @@ -176,7 +185,7 @@ bool isHourly(); bool isMonthly(); - bool saveLogProcedures(QString *myError, QString nameProc, QDate date); + bool saveLogProcedures(QString *errorStr, QString nameProc, QDate date); private: diff --git a/agrolib/dbMeteoPoints/dbAggregationsHandler.cpp b/agrolib/dbMeteoPoints/dbAggregationsHandler.cpp index 1b343b9f..e1b08ef8 100644 --- a/agrolib/dbMeteoPoints/dbAggregationsHandler.cpp +++ b/agrolib/dbMeteoPoints/dbAggregationsHandler.cpp @@ -35,28 +35,11 @@ Crit3DAggregationsDbHandler::~Crit3DAggregationsDbHandler() } } -QSqlDatabase Crit3DAggregationsDbHandler::db() const -{ - return _db; -} - - -QString Crit3DAggregationsDbHandler::error() const -{ - return _error; -} - -std::map Crit3DAggregationsDbHandler::mapIdMeteoVar() const -{ -return _mapIdMeteoVar; -} - bool Crit3DAggregationsDbHandler::saveAggrData(int nZones, QString aggrType, QString periodType, QDate startDate, QDate endDate, meteoVariable variable, - std::vector< std::vector > aggregatedValues, std::vector lonVector, std::vector latVector) + std::vector< std::vector > aggregatedValues) { initAggregatedTables(nZones, aggrType, periodType, startDate, endDate, variable); - writePointProperties(nZones, aggrType, lonVector, latVector); createTmpAggrTable(); @@ -102,7 +85,6 @@ bool Crit3DAggregationsDbHandler::saveAggrData(int nZones, QString aggrType, QSt bool Crit3DAggregationsDbHandler::writeAggregationZonesTable(QString name, QString filename, QString field) { - QSqlQuery qry(_db); qry.prepare( "INSERT INTO aggregation_zones (name, filename, shape_field)" @@ -117,29 +99,28 @@ bool Crit3DAggregationsDbHandler::writeAggregationZonesTable(QString name, QStri _error = qry.lastError().text(); return false; } - else - return true; + return true; } + bool Crit3DAggregationsDbHandler::writeRasterName(QString rasterName) { QSqlQuery qry(_db); - qry.prepare( "INSERT INTO zones (name)" - " VALUES (:name)" ); - + qry.prepare( "INSERT INTO zones (name) VALUES (:name)" ); qry.bindValue(":name", rasterName); - if( !qry.exec() ) + if(! qry.exec() ) { _error = qry.lastError().text(); return false; } - else - return true; + + return true; } + bool Crit3DAggregationsDbHandler::getRasterName(QString* rasterName) { QSqlQuery qry(_db); @@ -166,6 +147,7 @@ bool Crit3DAggregationsDbHandler::getRasterName(QString* rasterName) } } + bool Crit3DAggregationsDbHandler::getAggregationZonesReference(QString name, QString* filename, QString* field) { @@ -195,30 +177,32 @@ bool Crit3DAggregationsDbHandler::getAggregationZonesReference(QString name, QSt } } + void Crit3DAggregationsDbHandler::initAggregatedTables(int numZones, QString aggrType, QString periodType, QDate startDate, QDate endDate, meteoVariable variable) { - int idVariable = getIdfromMeteoVar(variable); for (int i = 1; i <= numZones; i++) { QString statement = QString("CREATE TABLE IF NOT EXISTS `%1_%2_%3` " - "(date_time TEXT, id_variable INTEGER, value REAL, PRIMARY KEY(date_time,id_variable))").arg(i).arg(aggrType).arg(periodType); + "(date_time TEXT, id_variable INTEGER, value REAL, PRIMARY KEY(date_time,id_variable))") + .arg(i).arg(aggrType, periodType); QSqlQuery qry(statement, _db); if( !qry.exec() ) { _error = qry.lastError().text(); } - statement = QString("DELETE FROM `%1_%2_%3` WHERE date_time >= DATE('%4') AND date_time < DATE('%5', '+1 day') AND id_variable = %6") - .arg(i).arg(aggrType).arg(periodType).arg(startDate.toString("yyyy-MM-dd")).arg(endDate.toString("yyyy-MM-dd")).arg(idVariable); + + statement = QString("DELETE FROM `%1_%2_%3` WHERE date_time >= DATE('%4') " + "AND date_time < DATE('%5', '+1 day') AND id_variable = %6") + .arg(i).arg(aggrType, periodType, startDate.toString("yyyy-MM-dd"), endDate.toString("yyyy-MM-dd")).arg(idVariable); qry = QSqlQuery(statement, _db); - if( !qry.exec() ) + if(! qry.exec() ) { _error = qry.lastError().text(); } } - } @@ -234,16 +218,16 @@ bool Crit3DAggregationsDbHandler::existIdPoint(const QString& idPoint) } -bool Crit3DAggregationsDbHandler::writePointProperties(int numZones, QString aggrType, std::vector lonVector, std::vector latVector) +bool Crit3DAggregationsDbHandler::writeAggregationPointProperties(int nrPoints, QString aggrType, + std::vector lonVector, std::vector latVector) { - if ( !_db.tables().contains(QLatin1String("point_properties")) ) + if (! _db.tables().contains(QLatin1String("point_properties")) ) { return false; } QSqlQuery qry(_db); - for (int i = 1; i <= numZones; i++) - + for (int i = 1; i <= nrPoints; i++) { QString id = QString::number(i) + "_" + aggrType; QString name = id; @@ -260,7 +244,7 @@ bool Crit3DAggregationsDbHandler::writePointProperties(int numZones, QString agg qry.bindValue(":altitude", 0); qry.bindValue(":is_active", 1); - if( !qry.exec() ) + if(! qry.exec() ) { _error = qry.lastError().text(); return false; @@ -271,6 +255,7 @@ bool Crit3DAggregationsDbHandler::writePointProperties(int numZones, QString agg return true; } + void Crit3DAggregationsDbHandler::createTmpAggrTable() { this->deleteTmpAggrTable(); @@ -390,16 +375,16 @@ int Crit3DAggregationsDbHandler::getIdfromMeteoVar(meteoVariable meteoVar) return key; } + QList Crit3DAggregationsDbHandler::getAggregations() { - QSqlQuery qry(_db); qry.prepare( "SELECT * FROM aggregations"); QString aggregation; QList aggregationList; - if( !qry.exec() ) + if(! qry.exec() ) { _error = qry.lastError().text(); } @@ -411,13 +396,16 @@ QList Crit3DAggregationsDbHandler::getAggregations() aggregationList.append(aggregation); } } + if (aggregationList.isEmpty()) { - _error = "name not found"; + _error = "aggregation table is empty."; } + return aggregationList; } + bool Crit3DAggregationsDbHandler::renameColumn(QString oldColumn, QString newColumn) { QSqlQuery qry(_db); diff --git a/agrolib/dbMeteoPoints/dbAggregationsHandler.h b/agrolib/dbMeteoPoints/dbAggregationsHandler.h index e0b15f82..ab0d1986 100644 --- a/agrolib/dbMeteoPoints/dbAggregationsHandler.h +++ b/agrolib/dbMeteoPoints/dbAggregationsHandler.h @@ -20,24 +20,33 @@ public: Crit3DAggregationsDbHandler(QString dbname); ~Crit3DAggregationsDbHandler(); - QSqlDatabase db() const; - QString error() const; + + QString error() const { return _error; } + QString name() const { return _db.databaseName(); } + QSqlDatabase db() const { return _db; } + + std::map mapIdMeteoVar() const { return _mapIdMeteoVar; } bool existIdPoint(const QString& idPoint); bool writeAggregationZonesTable(QString name, QString filename, QString field); bool getAggregationZonesReference(QString name, QString* filename, QString* field); void initAggregatedTables(int numZones, QString aggrType, QString periodType, QDate startDate, QDate endDate, meteoVariable variable); - bool writePointProperties(int numZones, QString aggrType, std::vector lonVector, std::vector latVector); - bool saveAggrData(int nZones, QString aggrType, QString periodType, QDate startDate, QDate endDate, meteoVariable variable, std::vector< std::vector > aggregatedValues, std::vector lonVector, std::vector latVector); - void createTmpAggrTable(); - void deleteTmpAggrTable(); + + bool writeAggregationPointProperties(int nrPoints, QString aggrType, std::vector lonVector, std::vector latVector); + + bool saveAggrData(int nZones, QString aggrType, QString periodType, QDate startDate, QDate endDate, + meteoVariable variable, std::vector< std::vector > aggregatedValues); + bool insertTmpAggr(QDate startDate, QDate endDate, meteoVariable variable, std::vector< std::vector > aggregatedValues, int nZones); bool saveTmpAggrData(QString aggrType, QString periodType, int nZones); + std::vector getAggrData(QString aggrType, QString periodType, int zone, QDate startDate, QDate endDate, meteoVariable variable); - std::map mapIdMeteoVar() const; + bool loadVariableProperties(); int getIdfromMeteoVar(meteoVariable meteoVar); + QList getAggregations(); + bool writeRasterName(QString rasterName); bool getRasterName(QString* rasterName); bool renameColumn(QString oldColumn, QString newColumn); @@ -47,6 +56,9 @@ QSqlDatabase _db; std::map _mapIdMeteoVar; QString _error; + + void createTmpAggrTable(); + void deleteTmpAggrTable(); }; #endif // DBAGGREGATIONSHANDLER_H diff --git a/agrolib/dbMeteoPoints/dbMeteoPointsHandler.cpp b/agrolib/dbMeteoPoints/dbMeteoPointsHandler.cpp index 5f02bc48..2c5dfc0d 100644 --- a/agrolib/dbMeteoPoints/dbMeteoPointsHandler.cpp +++ b/agrolib/dbMeteoPoints/dbMeteoPointsHandler.cpp @@ -76,28 +76,32 @@ Crit3DMeteoPointsDbHandler::~Crit3DMeteoPointsDbHandler() } -QString Crit3DMeteoPointsDbHandler::getDatasetURL(QString dataset) +QString Crit3DMeteoPointsDbHandler::getDatasetURL(QString dataset, bool &isOk) { - QSqlQuery qry(_db); - QString url = nullptr; - - qry.prepare( "SELECT URL FROM datasets WHERE dataset = :dataset"); - qry.bindValue(":dataset", dataset); + errorStr = ""; + QString queryStr = QString("SELECT URL FROM datasets WHERE dataset = '%1' OR dataset = '%2'").arg(dataset, dataset.toUpper()); - if( !qry.exec() ) + QSqlQuery qry(_db); + if(! qry.exec(queryStr)) { - qDebug() << qry.lastError(); + isOk = false; + errorStr = qry.lastError().text(); + return ""; } else { if (qry.next()) - url = qry.value(0).toString(); - + { + isOk = true; + return qry.value(0).toString(); + } else - qDebug( "Error: dataset not found" ); + { + isOk = false; + errorStr = "dataset " + dataset + " not found in the table 'datasets'"; + return ""; + } } - - return url; } @@ -162,6 +166,7 @@ QList Crit3DMeteoPointsDbHandler::getAllDatasetsList() return datasetList; } + QDateTime Crit3DMeteoPointsDbHandler::getFirstDate(frequencyType frequency) { QSqlQuery qry(_db); @@ -179,9 +184,10 @@ QDateTime Crit3DMeteoPointsDbHandler::getFirstDate(frequencyType frequency) qry.prepare( "SELECT name FROM sqlite_master WHERE type='table' AND name like :dayHour ESCAPE '^'"); qry.bindValue(":dayHour", "%^" + dayHour + "%"); - if( !qry.exec() ) + if(! qry.exec() ) { errorStr = qry.lastError().text(); + return firstDate; } else { @@ -242,9 +248,11 @@ QDateTime Crit3DMeteoPointsDbHandler::getLastDate(frequencyType frequency) qry.prepare( "SELECT name FROM sqlite_master WHERE type='table' AND name like :dayHour ESCAPE '^'"); qry.bindValue(":dayHour", "%^_" + dayHour + "%"); - if( !qry.exec() ) + QDateTime lastDate; + if(! qry.exec() ) { errorStr = qry.lastError().text(); + return lastDate; } else { @@ -255,7 +263,6 @@ QDateTime Crit3DMeteoPointsDbHandler::getLastDate(frequencyType frequency) } } - QDateTime lastDate; QDateTime currentLastDate; QDate myDate; QTime myTime; @@ -274,11 +281,13 @@ QDateTime Crit3DMeteoPointsDbHandler::getLastDate(frequencyType frequency) if (qry.next()) { dateStr = qry.value(0).toString(); - if (!dateStr.isEmpty()) + if (! dateStr.isEmpty()) { if (frequency == daily) { - currentLastDate = QDateTime::fromString(dateStr,"yyyy-MM-dd"); + myDate = QDate::fromString(dateStr, "yyyy-MM-dd"); + myTime = QTime(12, 0, 0, 0); + currentLastDate = QDateTime(myDate, myTime, Qt::UTC); } else if (frequency == hourly) { diff --git a/agrolib/dbMeteoPoints/dbMeteoPointsHandler.h b/agrolib/dbMeteoPoints/dbMeteoPointsHandler.h index e159561b..43c859f8 100644 --- a/agrolib/dbMeteoPoints/dbMeteoPointsHandler.h +++ b/agrolib/dbMeteoPoints/dbMeteoPointsHandler.h @@ -40,7 +40,7 @@ QString getErrorString() { return errorStr; } void setErrorString(QString str) { errorStr = str; } - QString getDatasetURL(QString dataset); + QString getDatasetURL(QString dataset, bool &isOk); bool setAndOpenDb(QString dbname_); QList getAllDatasetsList(); diff --git a/agrolib/dbMeteoPoints/download.cpp b/agrolib/dbMeteoPoints/download.cpp index c0eb5e46..65d1e0a7 100644 --- a/agrolib/dbMeteoPoints/download.cpp +++ b/agrolib/dbMeteoPoints/download.cpp @@ -1,4 +1,5 @@ #include "download.h" +#include "dbMeteoPointsHandler.h" #include @@ -55,7 +56,7 @@ bool Download::getPointProperties(QList datasetList) qDebug() << "err: " << error->errorString() << " -> " << error->offset; // check validity of the document - if(!doc.isNull() && doc.isArray()) + if(! doc.isNull() && doc.isArray() ) { QJsonArray jsonArr = doc.array(); @@ -71,7 +72,7 @@ bool Download::getPointProperties(QList datasetList) qDebug() << "jsonDataset: value is not string"; else foreach(QString item, _datasetsList) - if (jsonDataset == item) + if (jsonDataset.toString().toUpper() == item.toUpper()) { this->downloadMetadata(obj); } @@ -258,9 +259,9 @@ void Download::downloadMetadata(QJsonObject obj) _dbMeteo->writePointProperties(pointProp); } + bool Download::getPointPropertiesFromId(QString id, Crit3DMeteoPoint* pointProp) { - bool result = true; QEventLoop loop; @@ -291,7 +292,7 @@ bool Download::getPointPropertiesFromId(QString id, Crit3DMeteoPoint* pointProp) qDebug() << "err: " << error->errorString() << " -> " << error->offset; // check validity of the document - if(!doc.isNull() && doc.isArray()) + if(! doc.isNull() && doc.isArray()) { QJsonArray jsonArr = doc.array(); @@ -392,7 +393,8 @@ bool Download::getPointPropertiesFromId(QString id, Crit3DMeteoPoint* pointProp) } -bool Download::downloadDailyData(QDate startDate, QDate endDate, QString dataset, QList stations, QList variables, bool prec0024) +bool Download::downloadDailyData(const QDate &startDate, const QDate &endDate, const QString &dataset, + QList &stations, QList &variables, bool prec0024, QString &errorString) { QString area, product, refTime; QDate myDate; @@ -403,13 +405,15 @@ bool Download::downloadDailyData(QDate startDate, QDate endDate, QString dataset QList idVar; for (int i = 0; i < variableList.size(); i++) + { idVar.append(QString::number(variableList[i].id())); + } // create station tables _dbMeteo->initStationsDailyTables(startDate, endDate, stations, idVar); // attenzione: il reference time dei giornalieri è a fine giornata (ore 00 di day+1) - refTime = QString("reftime:>%1,<=%2").arg(startDate.toString("yyyy-MM-dd")).arg(endDate.addDays(1).toString("yyyy-MM-dd")); + refTime = QString("reftime:>%1,<=%2").arg(startDate.toString("yyyy-MM-dd"), endDate.addDays(1).toString("yyyy-MM-dd")); product = QString(";product: VM2,%1").arg(variables[0]); @@ -432,20 +436,27 @@ bool Download::downloadDailyData(QDate startDate, QDate endDate, QString dataset if (j == 0) { area = QString(";area: VM2,%1").arg(stations[countStation]); - j = j+1; - countStation = countStation+1; + countStation++; + j++; } while (countStation < stations.size() && j < maxStationSize) { area = area % QString(" or VM2,%1").arg(stations[countStation]); - countStation = countStation+1; - j = j+1; + countStation++; + j++; + } + + bool isOk; + url = QUrl(QString("%1/query").arg(_dbMeteo->getDatasetURL(dataset, isOk))); + if (! isOk) + { + errorString = _dbMeteo->getErrorString(); + return false; } QNetworkAccessManager* manager = new QNetworkAccessManager(this); connect(manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit())); - url = QUrl(QString("%1/query").arg(_dbMeteo->getDatasetURL(dataset))); request.setUrl(url); request.setRawHeader("Authorization", _authorization); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); @@ -460,7 +471,7 @@ bool Download::downloadDailyData(QDate startDate, QDate endDate, QString dataset if (reply->error() != QNetworkReply::NoError) { - qDebug( "Network Error" ); + errorString = "Network Error"; downloadOk = false; } else @@ -515,7 +526,7 @@ bool Download::downloadDailyData(QDate startDate, QDate endDate, QString dataset } } - if (!emptyLine) + if (! emptyLine) { downloadOk = _dbMeteo->saveDailyData(); } @@ -533,9 +544,9 @@ bool Download::downloadDailyData(QDate startDate, QDate endDate, QString dataset } -bool Download::downloadHourlyData(QDate startDate, QDate endDate, QString dataset, QList stations, QList variables) +bool Download::downloadHourlyData(const QDate &startDate, const QDate &endDate, const QString &dataset, + QList &stations, QList &variables, QString &errorString) { - QList variableList = _dbMeteo->getVariableProperties(variables); if (variableList.size() == 0) return false; @@ -562,7 +573,7 @@ bool Download::downloadHourlyData(QDate startDate, QDate endDate, QString datase endTime = endTime.addSecs(3600 * 24); // reftime - QString refTime = QString("reftime:>=%1,<=%2").arg(startTime.toString("yyyy-MM-dd hh:mm")).arg(endTime.toString("yyyy-MM-dd hh:mm")); + QString refTime = QString("reftime:>=%1,<=%2").arg(startTime.toString("yyyy-MM-dd hh:mm"), endTime.toString("yyyy-MM-dd hh:mm")); QEventLoop loop; @@ -587,10 +598,18 @@ bool Download::downloadHourlyData(QDate startDate, QDate endDate, QString datase countStation = countStation+1; j = j+1; } + + bool isOk; + url = QUrl(QString("%1/query").arg(_dbMeteo->getDatasetURL(dataset, isOk))); + if (! isOk) + { + errorString = _dbMeteo->getErrorString(); + return false; + } + QNetworkAccessManager* manager = new QNetworkAccessManager(this); connect(manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit())); - url = QUrl(QString("%1/query").arg(_dbMeteo->getDatasetURL(dataset))); request.setUrl(url); request.setRawHeader("Authorization", _authorization); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); @@ -604,7 +623,7 @@ bool Download::downloadHourlyData(QDate startDate, QDate endDate, QString datase if (reply->error() != QNetworkReply::NoError) { - qDebug( "Network Error" ); + errorString = "Network Error"; delete reply; delete manager; return false; diff --git a/agrolib/dbMeteoPoints/download.h b/agrolib/dbMeteoPoints/download.h index 1dab6823..96316a64 100644 --- a/agrolib/dbMeteoPoints/download.h +++ b/agrolib/dbMeteoPoints/download.h @@ -16,8 +16,12 @@ bool getPointPropertiesFromId(QString id, Crit3DMeteoPoint* pointProp); QMap getArmiketIdList(QList datasetList); void downloadMetadata(QJsonObject obj); - bool downloadDailyData(QDate startDate, QDate endDate, QString dataset, QList stations, QList variables, bool prec0024); - bool downloadHourlyData(QDate startDate, QDate endDate, QString dataset, QList stations, QList variables); + + bool downloadDailyData(const QDate &startDate, const QDate &endDate, const QString &dataset, + QList &stations, QList &variables, bool prec0024, QString &errorString); + + bool downloadHourlyData(const QDate &startDate, const QDate &endDate, const QString &dataset, + QList &stations, QList &variables, QString &errorString); DbArkimet* getDbArkimet(); diff --git a/agrolib/drought/drought.cpp b/agrolib/drought/drought.cpp index cfedf9fa..9ae9a29e 100644 --- a/agrolib/drought/drought.cpp +++ b/agrolib/drought/drought.cpp @@ -366,7 +366,7 @@ bool Drought::computeSpeiParameters() if ((float)n / (mySums.size()/12) >= minPerc / 100) { // Sort values - sorting::quicksortAscendingFloat(monthSeries, 0, monthSeries.size()-1); + sorting::quicksortAscendingFloat(monthSeries, 0, int(monthSeries.size())-1); // Compute probability weighted moments probabilityWeightedMoments(monthSeries, n, pwm, 0, 0, false); // Fit a Log Logistic probability function diff --git a/agrolib/gdal.pri b/agrolib/gdal.pri index 1d059af3..c7703404 100644 --- a/agrolib/gdal.pri +++ b/agrolib/gdal.pri @@ -4,19 +4,12 @@ # How to compile on windows: # # win32-msvc (Microsoft Visual C) -# - install GDAL (32 or 64 bit) from OSGeo4W https://trac.osgeo.org/osgeo4w/ -# - add GDAL_PATH to the system variables - example: GDAL_PATH = C:\OSGeo4W64 -# - add GDAL_DATA to the system variables - example: GDAL_DATA = C:\OSGeo4W64\share\epsg_csv -# - add PROJ_LIB to the system variables - example: PROJ_LIB = C:\OSGeo4W64\share\proj +# - install GDAL from OSGeo4W https://trac.osgeo.org/osgeo4w/ +# - add GDAL_PATH to the system variables - example: GDAL_PATH = C:\OSGeo4W +# - add GDAL_DATA to the system variables - example: GDAL_DATA = C:\OSGeo4W\share\epsg_csv +# - add PROJ_LIB to the system variables - example: PROJ_LIB = C:\OSGeo4W\share\proj # - add OSGeo4W\bin to the system path # -# win32-g++ (MinGW) -# Unfortunately it doesn't seem to work at the moment -# - install and update MSYS2 from https://www.msys2.org/ -# - run MSYS2 shell and install GDAL package - example: pacman -S mingw-w64-x86_64-gdal -# - add MSYS_PATH to system variables - example: MSYS_PATH = C:\msys64\mingw64 -# - add msys\mingw\bin to the system path -# #------------------------------------------------------------------------------------------ unix:!macx { @@ -28,21 +21,19 @@ unix:!macx { } win32-msvc { - LIBS += -L$$(GDAL_PATH)/lib/ -lgdal_i -lgeos_c + LIBS += -L$$(GDAL_PATH)/lib/ -lgdal_i INCLUDEPATH += $$(GDAL_PATH)/include DEPENDPATH += $$(GDAL_PATH)/include } win32-g++ { - LIBS += -L$$(MSYS_PATH)/lib/ -lgdal -lgeos -lgeos_c + LIBS += -L$$(GDAL_PATH)/lib/ -lgdal - INCLUDEPATH += $$(MSYS_PATH)/include - DEPENDPATH += $$(MSYS_PATH)/include + INCLUDEPATH += $$(GDAL_PATH)/include + DEPENDPATH += $$(GDAL_PATH)/include PRE_TARGETDEPS += $$(MSYS_PATH)/lib/libgdal.a - PRE_TARGETDEPS += $$(MSYS_PATH)/lib/libgeos.dll.a - PRE_TARGETDEPS += $$(MSYS_PATH)/lib/libgeos_c.dll.a } mac { diff --git a/agrolib/gdalHandler/gdalHandler.pro b/agrolib/gdalHandler/gdalHandler.pro index 8e9c39a2..a823f52b 100644 --- a/agrolib/gdalHandler/gdalHandler.pro +++ b/agrolib/gdalHandler/gdalHandler.pro @@ -34,13 +34,11 @@ SOURCES += \ gdalExtensions.cpp \ gdalRasterFunctions.cpp \ gdalShapeFunctions.cpp \ -# gdalShapeIntersection.cpp HEADERS += \ gdalExtensions.h \ gdalRasterFunctions.h \ gdalShapeFunctions.h \ -# gdalShapeIntersection.h include(../gdal.pri) diff --git a/agrolib/gis/color.cpp b/agrolib/gis/color.cpp index 36fa33ec..1ae2aad2 100644 --- a/agrolib/gis/color.cpp +++ b/agrolib/gis/color.cpp @@ -54,7 +54,9 @@ Crit3DColorScale::Crit3DColorScale() _minimum = NODATA; _maximum = NODATA; - _isRangeBlocked = false; + _isFixedRange = false; + _isHideOutliers = false; + _isTransparent = false; _classification = classificationMethod::EqualInterval; } @@ -179,11 +181,12 @@ bool setDTMScale(Crit3DColorScale* myScale) bool setLAIScale(Crit3DColorScale* myScale) { - myScale->initialize(3, 256); + myScale->initialize(4, 256); - myScale->keyColor[0] = Crit3DColor(200, 150, 0); /*!< ocra */ - myScale->keyColor[1] = Crit3DColor(32, 150, 32); /*!< dark green */ - myScale->keyColor[2] = Crit3DColor(0, 255, 0); /*!< green */ + myScale->keyColor[0] = Crit3DColor(200, 160, 0); /*!< ocra */ + myScale->keyColor[1] = Crit3DColor(160, 160, 0); /*!< yellow */ + myScale->keyColor[2] = Crit3DColor(32, 160, 32); /*!< dark green */ + myScale->keyColor[3] = Crit3DColor(0, 255, 0); /*!< green */ return(myScale->classify()); } @@ -205,19 +208,13 @@ bool setTemperatureScale(Crit3DColorScale* myScale) bool setSlopeStabilityScale(Crit3DColorScale* myScale) { - myScale->initialize(11, 220); + myScale->initialize(5, 256); myScale->keyColor[0] = Crit3DColor(128, 0, 128); /*!< violet */ myScale->keyColor[1] = Crit3DColor(255, 0, 0); /*!< red */ myScale->keyColor[2] = Crit3DColor(255, 255, 0); /*!< yellow */ - myScale->keyColor[3] = Crit3DColor(128, 220, 0); /*!< yellow/green */ - myScale->keyColor[4] = Crit3DColor(64, 196, 64); /*!< green */ - myScale->keyColor[5] = Crit3DColor(64, 196, 64); /*!< green */ - myScale->keyColor[6] = Crit3DColor(64, 196, 64); /*!< green */ - myScale->keyColor[7] = Crit3DColor(64, 196, 64); /*!< green */ - myScale->keyColor[8] = Crit3DColor(64, 196, 64); /*!< green */ - myScale->keyColor[9] = Crit3DColor(64, 196, 64); /*!< green */ - myScale->keyColor[10] = Crit3DColor(64, 196, 64); /*!< green */ + myScale->keyColor[3] = Crit3DColor(64, 196, 64); /*!< green */ + myScale->keyColor[4] = Crit3DColor(128, 255, 128); /*!< light green */ return(myScale->classify()); } @@ -239,7 +236,7 @@ bool setAnomalyScale(Crit3DColorScale* myScale) bool setPrecipitationScale(Crit3DColorScale* myScale) { - myScale->initialize(6, 256); + myScale->initialize(6, 252); myScale->keyColor[0] = Crit3DColor(255, 255, 255); /*!< white */ myScale->keyColor[1] = Crit3DColor(0, 0, 255); /*!< blue */ @@ -369,6 +366,23 @@ bool reverseColorScale(Crit3DColorScale* myScale) } +void mixColor(const Crit3DColor &backColor, const Crit3DColor &foreColor, Crit3DColor &colorOut, float alpha) +{ + if (alpha == 0) + { + colorOut.red = backColor.red; + colorOut.green = backColor.green; + colorOut.blue = backColor.blue; + } + else + { + colorOut.red = std::min(255, int(backColor.red * (1. - alpha)) + int(foreColor.red * alpha)); + colorOut.green = std::min(255, int(backColor.green * (1. - alpha)) + int(foreColor.green * alpha)); + colorOut.blue = std::min(255, int(backColor.blue * (1. - alpha)) +int( foreColor.blue * alpha)); + } +} + + /*! * \brief roundColorScale round colorScale values on the second (or third) digit of each range. * It requires that nrColors is a multiply of nrIntervals for a correct visualization in the colors legend. diff --git a/agrolib/gis/color.h b/agrolib/gis/color.h index 57b4d125..64a1fe88 100644 --- a/agrolib/gis/color.h +++ b/agrolib/gis/color.h @@ -15,7 +15,7 @@ short blue; Crit3DColor(); - Crit3DColor(short,short,short); + Crit3DColor(short, short, short); }; class Crit3DColorScale { @@ -23,8 +23,10 @@ private: unsigned int _nrColors, _nrKeyColors; std::vector color; - float _minimum, _maximum; - bool _isRangeBlocked; + double _minimum, _maximum; + bool _isFixedRange; + bool _isHideOutliers; + bool _isTransparent; int _classification; public: @@ -38,18 +40,25 @@ unsigned int nrColors() { return _nrColors; } unsigned int nrKeyColors() { return _nrKeyColors; } - float minimum() { return _minimum; } - void setMinimum(float min) { _minimum = min; } + double minimum() { return _minimum; } + void setMinimum(double min) { _minimum = min; } - float maximum() { return _maximum; } - void setMaximum(float max) { _maximum = max; } + double maximum() { return _maximum; } + void setMaximum(double max) { _maximum = max; } Crit3DColor* getColor(float myValue); unsigned int getColorIndex(float myValue); bool setRange(float minimum, float maximum); - void setRangeBlocked(bool blocked) { _isRangeBlocked = blocked; } - bool isRangeBlocked() { return _isRangeBlocked; } + + void setFixedRange(bool fixedRange) { _isFixedRange = fixedRange; } + bool isFixedRange() { return _isFixedRange; } + + void setHideOutliers(bool hideOutliers) { _isHideOutliers = hideOutliers; } + bool isHideOutliers() { return _isHideOutliers; } + + void setTransparent(bool transparent) { _isTransparent = transparent; } + bool isTransparent() { return _isTransparent; } }; bool setDefaultScale(Crit3DColorScale* myScale); @@ -70,5 +79,7 @@ bool setSurfaceWaterScale(Crit3DColorScale* myScale); bool setLAIScale(Crit3DColorScale* myScale); + void mixColor(const Crit3DColor &backColor, const Crit3DColor &foreColor, Crit3DColor &colorOut, float alpha); + #endif // CRIT3DCOLOR_H diff --git a/agrolib/gis/gis.cpp b/agrolib/gis/gis.cpp index 3d02f789..b4754afb 100644 --- a/agrolib/gis/gis.cpp +++ b/agrolib/gis/gis.cpp @@ -287,14 +287,13 @@ namespace gis bool Crit3DRasterGrid::initializeParameters(const Crit3DRasterHeader& initHeader) { - if (!parametersCell.empty()) - parametersCell.clear(); - parametersCell.resize(initHeader.nrRows*initHeader.nrCols); - for (int i = 0; i < parametersCell.size(); i++) + singleCell.clear(); + singleCell.resize(initHeader.nrRows*initHeader.nrCols); + for (int i = 0; i < int(singleCell.size()); i++) { - parametersCell[i].row = i / initHeader.nrCols; - parametersCell[i].col = i % initHeader.nrCols; - parametersCell[i].fittingParameters.clear(); + singleCell[i].row = i / initHeader.nrCols; + singleCell[i].col = i % initHeader.nrCols; + singleCell[i].fittingParameters.clear(); } return true; @@ -302,12 +301,12 @@ namespace gis bool Crit3DRasterGrid::initializeParametersLatLonHeader(const Crit3DLatLonHeader& latLonHeader) { - parametersCell.resize(latLonHeader.nrRows*latLonHeader.nrCols); - for (int i = 0; i < parametersCell.size(); i++) + singleCell.resize(latLonHeader.nrRows*latLonHeader.nrCols); + for (int i = 0; i < int(singleCell.size()); i++) { - parametersCell[i].row = i / latLonHeader.nrCols; - parametersCell[i].col = i % latLonHeader.nrCols; - parametersCell[i].fittingParameters.clear(); + singleCell[i].row = i / latLonHeader.nrCols; + singleCell[i].col = i % latLonHeader.nrCols; + singleCell[i].fittingParameters.clear(); } return true; @@ -498,8 +497,8 @@ namespace gis int index = row * header->nrCols + col; - if (index < parametersCell.size()) - parameters = parametersCell[index].fittingParameters; + if (index < int(singleCell.size())) + parameters = singleCell[index].fittingParameters; return parameters; @@ -512,68 +511,76 @@ namespace gis return false; int index = row * header->nrCols + col; - parametersCell[index].fittingParameters = parameters; + singleCell[index].fittingParameters = parameters; return true; } - std::vector> Crit3DRasterGrid::prepareParameters(int row, int col) + std::vector> Crit3DRasterGrid::prepareParameters(int row, int col, std::vector activeList) { std::vector> tempProxyVector; - std::vector tempParVector; tempProxyVector.clear(); - tempParVector.clear(); - double avg; - int counter; - int l, i, j, k; - int index; + tempProxyVector.resize(activeList.size()); + int l, m, k, p; + l = 0; + m = 0; + std::vector avg; + int counter, index; bool findFirst = 0; if (isOutOfGrid(row, col)) return tempProxyVector; - //look for the first cell that has data in it. if there isn't any, return empty vector - for (i = row-1; i < row+2; i++) + for (unsigned int i = 0; i < activeList.size(); i++) { - for (j = col-1; j < col+2; j++) + findFirst = 0; + if (activeList[i]) { - index = i * header->nrCols + j; - if (index >= 0 && index < parametersCell.size() && !parametersCell[index].fittingParameters.empty() && (i != row || j !=col)) - findFirst = 1; - if (findFirst==1) break; - } - if (findFirst==1) break; - } + //look for the first cell that has data for that proxy. if there isn't any, return empty vector + for (l = row-1; l < row+2; l++) + { + for (m = col-1; m < col+2; m++) + { + index = l * header->nrCols + m; + if (index >= 0 && index < int(singleCell.size()) && (singleCell[index].fittingParameters.size() > i && !singleCell[index].fittingParameters[i].empty()) && (l != row || m !=col)) { + findFirst = 1; + } + if (findFirst==1) break; + } + if (findFirst==1) break; + } - //starting from firt full cell, look at the remaining ones and calculate all the average parameter values - for (k = 0; k < parametersCell[index].fittingParameters.size(); k++) - { - for (l = 0; l < parametersCell[index].fittingParameters[k].size(); l++) - { - avg = 0; + if (findFirst == 0) + continue; + + //you're on a specific proxy rn. cycle through the cells, calculate the avg + avg.clear(); + avg.resize(singleCell[index].fittingParameters[i].size()); counter = 0; - for (int h = i; h < row+2; h++) + + for (k = l; k < row+2; k++) { - for (int m = j; m < col+2; m++) + for (p = m; p < col+2; p++) { - index = h * header->nrCols + m; - if (index >= 0 && index < parametersCell.size() && !parametersCell[index].fittingParameters.empty() && (i != row || j !=col)) - { - avg += parametersCell[index].fittingParameters[k][l]; + index = k * header->nrCols + p; + if (index >= 0 && index < int(singleCell.size()) && singleCell[index].fittingParameters.size() > i && !singleCell[index].fittingParameters[i].empty()) { + for (unsigned int o = 0; o < avg.size(); o++) + { + avg[o] += singleCell[index].fittingParameters[i][o]; + + } counter++; } } } - //push back the vector of averages - tempParVector.push_back(avg/counter); - index = i*header->nrCols+j; + for (unsigned int o = 0; o < avg.size(); o++) + avg[o] /= counter; + + tempProxyVector[i] = avg; } - tempProxyVector.push_back(tempParVector); - tempParVector.clear(); } return tempProxyVector; - } void convertFlagToNodata(Crit3DRasterGrid& myGrid) @@ -624,12 +631,13 @@ namespace gis } /*! no values */ - if (isFirstValue) return false; + if (isFirstValue) + return false; myGrid->maximum = maximum; myGrid->minimum = minimum; - if (! myGrid->colorScale->isRangeBlocked()) + if (! myGrid->colorScale->isFixedRange()) { myGrid->colorScale->setRange(minimum, maximum); } @@ -726,7 +734,7 @@ namespace gis v->col = int(floor((p.x - myHeader.llCorner.x) / myHeader.cellSize)); } - void getGridRowColFromXY (const Crit3DLatLonHeader& myHeader, double myX, double myY, int *row, int *col) + void getGridRowColFromLonLat(const Crit3DLatLonHeader& myHeader, double myX, double myY, int *row, int *col) { *row = int(floor((myY - myHeader.llCorner.latitude) / myHeader.dy)); *col = int(floor((myX - myHeader.llCorner.longitude) / myHeader.dx)); @@ -772,6 +780,12 @@ namespace gis *myY = myHeader.llCorner.y + myHeader.cellSize * (myHeader.nrRows - row - 0.5); } + void getUtmXYFromRowCol(Crit3DRasterHeader *myHeader, int row, int col, double* myX, double* myY) + { + *myX = myHeader->llCorner.x + myHeader->cellSize * (col + 0.5); + *myY = myHeader->llCorner.y + myHeader->cellSize * (myHeader->nrRows - row - 0.5); + } + void getLatLonFromRowCol(const Crit3DLatLonHeader& latLonHeader, int row, int col, double* lat, double* lon) { *lon = latLonHeader.llCorner.longitude + latLonHeader.dx * (col + 0.5); @@ -809,7 +823,6 @@ namespace gis gis::utmToLatLon(gisSettings.utmZone, gisSettings.startLocation.latitude, utmX, utmY, myLat, myLon); } - void getLatLonFromUtm(const Crit3DGisSettings& gisSettings, const Crit3DUtmPoint& utmPoint, Crit3DGeoPoint& geoPoint) { gis::utmToLatLon(gisSettings.utmZone, gisSettings.startLocation.latitude, utmPoint.x, utmPoint.y, &(geoPoint.latitude), &(geoPoint.longitude)); @@ -896,6 +909,11 @@ namespace gis latLonToUtmForceZone(zoneNumber, geoPoint.latitude, geoPoint.longitude, &(utmPoint->x), &(utmPoint->y)); } + void getUtmFromLatLon(const Crit3DGisSettings& gisSettings, double latitude, double longitude, double *utmX, double *utmY) + { + latLonToUtmForceZone(gisSettings.utmZone, latitude, longitude, utmX, utmY); + } + /*! \brief equivalent to latLonToUtm forcing UTM zone. @@ -1328,24 +1346,27 @@ namespace gis { float value = rasterRef.getValueFromRowCol(row,col); float aspect = aspectMap.getValueFromRowCol(row,col); - if ( isEqual(value, rasterRef.header->flag) - || isEqual(aspect, aspectMap.header->flag) ) - return false; + if (isEqual(value, rasterRef.header->flag) || isEqual(aspect, aspectMap.header->flag)) + { + return false; + } int r = 0; int c = 0; - if (aspect > 135 && aspect < 225) + if (aspect >= 135 && aspect <= 225) r = 1; - else if ((aspect < 45) || (aspect > 315)) + else if ((aspect <= 45) || (aspect >= 315)) r = -1; - if (aspect > 45 && aspect < 135) + if (aspect >= 45 && aspect <= 135) c = 1; - else if (aspect > 225 && aspect < 315) + else if (aspect >= 225 && aspect <= 315) c = -1; float valueBoundary = rasterRef.getValueFromRowCol(row + r, col + c); - return isEqual(valueBoundary, rasterRef.header->flag); + bool isBoundary = isEqual(valueBoundary, rasterRef.header->flag); + + return isBoundary; } @@ -1580,17 +1601,17 @@ namespace gis isEqual(first.header->llCorner.y, second.header->llCorner.y)); } + void resampleGrid(const gis::Crit3DRasterGrid& oldGrid, gis::Crit3DRasterGrid* newGrid, - gis::Crit3DRasterHeader* header, aggregationMethod elab, float nodataThreshold) + gis::Crit3DRasterHeader* newHeader, aggregationMethod elab, float nodataRatioThreshold) { - *(newGrid->header) = *header; + *(newGrid->header) = *newHeader; + + double resampleFactor = newGrid->header->cellSize / oldGrid.header->cellSize; - double factor = newGrid->header->cellSize / oldGrid.header->cellSize; int row, col, tmpRow, tmpCol, nrValues, maxValues; - float value, tmpValue; - double x, y; gis::Crit3DPoint myLL, myUR; - std::vector values; + std::vector values; newGrid->initializeGrid(); @@ -1599,42 +1620,56 @@ namespace gis { newGrid->value[row][col] = newGrid->header->flag; - value = NODATA; - - if (factor < 1 || elab == aggrCenter) + float value = NODATA; + if (resampleFactor < 1. || elab == aggrCenter) { + double x, y; newGrid->getXY(row, col, x, y); oldGrid.getRowCol(x, y, tmpRow, tmpCol); if (! gis::isOutOfGridRowCol(tmpRow, tmpCol, oldGrid)) + { value = oldGrid.value[tmpRow][tmpCol]; + } } else { - newGrid->getXY(row, col, x, y); - myLL.utm.x = x - (newGrid->header->cellSize / 2); - myLL.utm.y = y - (newGrid->header->cellSize / 2); - myUR.utm.x = x + (newGrid->header->cellSize / 2); - myUR.utm.y = y + (newGrid->header->cellSize / 2); + double x0, y0; + newGrid->getXY(row, col, x0, y0); + myLL.utm.x = x0 - (newGrid->header->cellSize / 2); + myLL.utm.y = y0 - (newGrid->header->cellSize / 2); + myUR.utm.x = x0 + (newGrid->header->cellSize / 2); + myUR.utm.y = y0 + (newGrid->header->cellSize / 2); + + double step = oldGrid.header->cellSize * 0.5; values.clear(); maxValues = 0; - double step = oldGrid.header->cellSize * 0.5; - for (x = myLL.utm.x; x <= myUR.utm.x; x += step) - for (y = myLL.utm.y; y <= myUR.utm.y; y += step) + + double x = myLL.utm.x; + while(x <= myUR.utm.x) + { + double y = myLL.utm.y; + while(y <= myUR.utm.y) { maxValues++; - tmpValue = gis::getValueFromXY(oldGrid, x, y); + float tmpValue = gis::getValueFromXY(oldGrid, x, y); if (! isEqual(tmpValue, oldGrid.header->flag)) + { values.push_back(tmpValue); - } + } + y += step; + } + x += step; + } nrValues = int(values.size()); + if (maxValues > 0) { - if ((float(nrValues) / float(maxValues)) > nodataThreshold) + if ((float(nrValues) / float(maxValues)) > nodataRatioThreshold) { if (elab == aggrAverage) - value = statistics::mean(values, nrValues); + value = statistics::mean(values); else if (elab == aggrMedian) value = sorting::percentile(values, nrValues, 50, true); else if (elab == aggrPrevailing) @@ -1643,14 +1678,17 @@ namespace gis } } - if (! isEqual(value, NODATA)) newGrid->value[row][col] = value; + if (! isEqual(value, NODATA)) + { + newGrid->value[row][col] = value; + } } gis::updateMinMaxRasterGrid(newGrid); newGrid->isLoaded = true; - } + bool temporalYearlyInterpolation(const gis::Crit3DRasterGrid& firstGrid, const gis::Crit3DRasterGrid& secondGrid, int myYear, float minValue, float maxValue, gis::Crit3DRasterGrid* outGrid) { @@ -1687,5 +1725,80 @@ namespace gis return true; } + + + bool clipRasterWithRaster(gis::Crit3DRasterGrid* refRaster, gis::Crit3DRasterGrid* maskRaster, gis::Crit3DRasterGrid* outputRaster) + { + if (refRaster == nullptr || maskRaster == nullptr || outputRaster == nullptr) + return false; + + gis::Crit3DRasterGrid* tmpRaster = new gis::Crit3DRasterGrid(); + tmpRaster->initializeGrid(*(refRaster->header)); + + bool isFirst = true; + long firstRow, lastRow, firstCol, lastCol; + double x, y; + for (long row = 0; row < refRaster->header->nrRows; row++) + { + for (long col = 0; col < refRaster->header->nrCols; col++) + { + gis::getUtmXYFromRowCol(refRaster->header, row, col, &x, &y); + if (! isEqual(maskRaster->getValueFromXY(x, y), maskRaster->header->flag)) + { + tmpRaster->value[row][col] = refRaster->value[row][col]; + if (isFirst) + { + firstRow = row; + lastRow = row; + firstCol = col; + lastCol = col; + isFirst = false; + } + else + { + firstRow = std::min(firstRow, row); + firstCol = std::min(firstCol, col); + lastRow = std::max(lastRow, row); + lastCol = std::max(lastCol, col); + } + } + } + } + + // check no data + if (isFirst) + { + tmpRaster->clear(); + return false; + } + + // new header + gis::Crit3DRasterHeader header; + header = *(refRaster->header); + header.nrRows = lastRow - firstRow + 1; + header.nrCols = lastCol - firstCol + 1; + header.llCorner.x = refRaster->header->llCorner.x + refRaster->header->cellSize * firstCol; + header.llCorner.y = refRaster->header->llCorner.y + refRaster->header->cellSize * (refRaster->header->nrRows - (lastRow +1)); + + // output raster + outputRaster->initializeGrid(header); + + for (long row = 0; row < outputRaster->header->nrRows; row++) + { + for (long col = 0; col < outputRaster->header->nrCols; col++) + { + float value = tmpRaster->value[row + firstRow][col + firstCol]; + if (! isEqual (value, tmpRaster->header->flag)) + outputRaster->value[row][col] = value; + } + } + + // clean memory + tmpRaster->clear(); + + gis::updateMinMaxRasterGrid(outputRaster); + return true; + } + } diff --git a/agrolib/gis/gis.h b/agrolib/gis/gis.h index 496c4327..589e27ad 100644 --- a/agrolib/gis/gis.h +++ b/agrolib/gis/gis.h @@ -139,7 +139,7 @@ Crit3DRasterCell(); }; - struct RasterGridParameters { + struct RasterGridCell { public: int row; int col; @@ -155,7 +155,7 @@ float minimum, maximum; bool isLoaded; Crit3DTime mapTime; - std::vector parametersCell; + std::vector singleCell; Crit3DUtmPoint* utmPoint(int myRow, int myCol); void getXY(int myRow, int myCol, double &x, double &y) const; @@ -191,7 +191,7 @@ float getValueFromXY(double x, double y) const; std::vector> getParametersFromRowCol(int row, int col); bool setParametersForRowCol(int row, int col, std::vector> parameters); - std::vector> prepareParameters(int row, int col); + std::vector> prepareParameters(int row, int col, std::vector activeList); Crit3DTime getMapTime() const; void setMapTime(const Crit3DTime &value); @@ -216,7 +216,7 @@ void getRowColFromXY(const Crit3DRasterHeader& myHeader, double myX, double myY, int *row, int *col); void getRowColFromXY(const Crit3DRasterHeader& myHeader, const Crit3DUtmPoint& p, int *row, int *col); void getRowColFromXY(const Crit3DRasterHeader& myHeader, const Crit3DUtmPoint& p, Crit3DRasterCell* v); - void getGridRowColFromXY(const Crit3DLatLonHeader& myHeader, double myX, double myY, int *row, int *col); + void getGridRowColFromLonLat(const Crit3DLatLonHeader& myHeader, double myX, double myY, int *row, int *col); void getRowColFromLatLon(const Crit3DLatLonHeader &latLonHeader, const Crit3DGeoPoint& p, int *myRow, int *myCol); bool isOutOfGridRowCol(int myRow, int myCol, const Crit3DRasterGrid &rasterGrid); @@ -224,6 +224,7 @@ void getUtmXYFromRowColSinglePrecision(const Crit3DRasterGrid& rasterGrid, int myRow, int myCol,float* myX,float* myY); void getUtmXYFromRowColSinglePrecision(const Crit3DRasterHeader& myHeader, int myRow, int myCol,float* myX,float* myY); void getUtmXYFromRowCol(const Crit3DRasterHeader& myHeader,int myRow, int myCol, double* myX, double* myY); + void getUtmXYFromRowCol(Crit3DRasterHeader *myHeader, int row, int col, double* myX, double* myY); void getLatLonFromRowCol(const Crit3DLatLonHeader &latLonHeader, int myRow, int myCol, double* lat, double* lon); void getLatLonFromRowCol(const Crit3DLatLonHeader &latLonHeader, const Crit3DRasterCell& v, Crit3DGeoPoint* p); @@ -242,7 +243,9 @@ bool getNorthernEmisphere(); void getLatLonFromUtm(const Crit3DGisSettings& gisSettings, double utmX,double utmY, double *myLat, double *myLon); void getLatLonFromUtm(const Crit3DGisSettings& gisSettings, const Crit3DUtmPoint& utmPoint, Crit3DGeoPoint& geoPoint); + void getUtmFromLatLon(int zoneNumber, const Crit3DGeoPoint& geoPoint, Crit3DUtmPoint* utmPoint); + void getUtmFromLatLon(const Crit3DGisSettings& gisSettings, double latitude, double longitude, double *utmX, double *utmY); void latLonToUtm(double lat, double lon,double *utmEasting,double *utmNorthing,int *zoneNumber); void latLonToUtmForceZone(int zoneNumber, double lat, double lon, double *utmEasting, double *utmNorthing); @@ -251,17 +254,21 @@ bool openRaster(std::string fileName, Crit3DRasterGrid *rasterGrid, int currentUtmZone, std::string &errorStr); - bool readEsriGrid(std::string fileName, Crit3DRasterGrid* rasterGrid, std::string &errorStr); - bool writeEsriGrid(std::string fileName, Crit3DRasterGrid *rasterGrid, std::string &errorStr); + bool readEsriGrid(const std::string &fileName, Crit3DRasterGrid* rasterGrid, std::string &errorStr); + bool writeEsriGrid(const std::string &fileName, Crit3DRasterGrid *rasterGrid, std::string &errorStr); bool readEnviGrid(std::string fileName, Crit3DRasterGrid* rasterGrid, int currentUtmZone, std::string &errorStr); bool writeEnviGrid(std::string fileName, int utmZone, Crit3DRasterGrid *rasterGrid, std::string &errorStr); bool mapAlgebra(Crit3DRasterGrid* myMap1, Crit3DRasterGrid* myMap2, Crit3DRasterGrid *outputMap, operationType myOperation); bool mapAlgebra(Crit3DRasterGrid* myMap1, float myValue, Crit3DRasterGrid *outputMap, operationType myOperation); + bool prevailingMap(const Crit3DRasterGrid& inputMap, Crit3DRasterGrid *outputMap); float prevailingValue(const std::vector &valueList); + bool clipRasterWithRaster(gis::Crit3DRasterGrid* refRaster, gis::Crit3DRasterGrid* maskRaster, + gis::Crit3DRasterGrid* outputRaster); + bool computeLatLonMaps(const gis::Crit3DRasterGrid& rasterGrid, gis::Crit3DRasterGrid* latMap, gis::Crit3DRasterGrid* lonMap, const gis::Crit3DGisSettings& gisSettings); @@ -280,7 +287,7 @@ float closestDistanceFromGrid(Crit3DPoint myPoint, const gis::Crit3DRasterGrid& dem); bool compareGrids(const gis::Crit3DRasterGrid& first, const gis::Crit3DRasterGrid& second); void resampleGrid(const gis::Crit3DRasterGrid& oldGrid, gis::Crit3DRasterGrid* newGrid, - Crit3DRasterHeader* header, aggregationMethod elab, float nodataThreshold); + Crit3DRasterHeader* newHeader, aggregationMethod elab, float nodataRatioThreshold); bool temporalYearlyInterpolation(const gis::Crit3DRasterGrid& firstGrid, const gis::Crit3DRasterGrid& secondGrid, int myYear, float minValue, float maxValue, gis::Crit3DRasterGrid* outGrid); } diff --git a/agrolib/gis/gisIO.cpp b/agrolib/gis/gisIO.cpp index f81fcbeb..62949938 100644 --- a/agrolib/gis/gisIO.cpp +++ b/agrolib/gis/gisIO.cpp @@ -112,17 +112,17 @@ namespace gis * \param error string * \return true on success, false otherwise */ - bool readEsriGridHeader(string fileName, gis::Crit3DRasterHeader *header, string &errorStr) + bool readEsriGridHeader(const string &fileName, gis::Crit3DRasterHeader *header, string &errorStr) { string myLine, myKey, upKey, valueStr; int nrKeys = 0; - fileName += ".hdr"; - ifstream myFile (fileName.c_str()); + string myFileName = fileName + ".hdr"; + ifstream myFile (myFileName.c_str()); - if (!myFile.is_open()) + if (! myFile.is_open()) { - errorStr = "Missing file: " + fileName; + errorStr = "Missing file: " + myFileName; return false; } @@ -237,7 +237,7 @@ namespace gis // remove the curly braces, split the values ​​and remove the spaces cleanBraces(valueStr); vector infoStr = splitCommaDelimited(valueStr); - for (int i = 0; i < infoStr.size(); i++) + for (int i = 0; i < int(infoStr.size()); i++) { cleanSpaces(infoStr[i]); } @@ -315,7 +315,7 @@ namespace gis * \param error string * \return true on success, false otherwise */ - bool readRasterFloatData(string fileName, gis::Crit3DRasterGrid *rasterGrid, string &error) + bool readRasterFloatData(const string &fileName, gis::Crit3DRasterGrid *rasterGrid, string &error) { FILE* filePointer; @@ -382,12 +382,12 @@ namespace gis * \param error string pointer * \return true on success, false otherwise */ - bool writeEsriGridHeader(string myFileName, gis::Crit3DRasterHeader *myHeader, string &error) + bool writeEsriGridHeader(const string &fileName, gis::Crit3DRasterHeader *myHeader, string &error) { - myFileName += ".hdr"; + string myFileName = fileName + ".hdr"; ofstream myFile (myFileName.c_str()); - if (!myFile.is_open()) + if (! myFile.is_open()) { error = "File .hdr error."; return false; @@ -429,9 +429,9 @@ namespace gis * \param error string pointer * \return true on success, false otherwise */ - bool writeEsriGridFlt(string myFileName, gis::Crit3DRasterGrid* myGrid, string &error) + bool writeEsriGridFlt(const string &fileName, gis::Crit3DRasterGrid* myGrid, string &error) { - myFileName += ".flt"; + string myFileName = fileName + ".flt"; FILE* filePointer; @@ -454,13 +454,15 @@ namespace gis * \brief Write a ESRI float raster (.hdr and .flt) * \return true on success, false otherwise */ - bool writeEsriGrid(string fileName, Crit3DRasterGrid* rasterGrid, string &error) + bool writeEsriGrid(const string &fileName, Crit3DRasterGrid* rasterGrid, string &errorStr) { - if (gis::writeEsriGridHeader(fileName, rasterGrid->header, error)) - if (gis::writeEsriGridFlt(fileName, rasterGrid, error)) - return true; + if (! gis::writeEsriGridHeader(fileName, rasterGrid->header, errorStr)) + return false; - return false; + if (! gis::writeEsriGridFlt(fileName, rasterGrid, errorStr)) + return false; + + return true; } @@ -468,15 +470,15 @@ namespace gis * \brief Read a ESRI float raster (.hdr and .flt) * \return true on success, false otherwise */ - bool readEsriGrid(string fileName, Crit3DRasterGrid* rasterGrid, string &errorStr) + bool readEsriGrid(const string &fileName, Crit3DRasterGrid* rasterGrid, string &errorStr) { if (rasterGrid == nullptr) return false; rasterGrid->clear(); if(gis::readEsriGridHeader(fileName, rasterGrid->header, errorStr)) { - fileName += ".flt"; - if (gis::readRasterFloatData(fileName, rasterGrid, errorStr)) + string fltFileName = fileName + ".flt"; + if (gis::readRasterFloatData(fltFileName, rasterGrid, errorStr)) { gis::updateMinMaxRasterGrid(rasterGrid); rasterGrid->isLoaded = true; @@ -571,7 +573,7 @@ namespace gis } myFile << "ENVI\n"; - myFile << "description = {CRITERIA3D raster grid}\n"; + myFile << "description = {raster grid}\n"; myFile << "samples = " << rasterGrid->header->nrCols << "\n"; myFile << "lines = " << rasterGrid->header->nrRows << "\n"; myFile << "bands = 1\n"; diff --git a/agrolib/grapevine/grapevine.cpp b/agrolib/grapevine/grapevine.cpp index 3e112e07..83e04c5d 100644 --- a/agrolib/grapevine/grapevine.cpp +++ b/agrolib/grapevine/grapevine.cpp @@ -21,9 +21,7 @@ const float LAIMIN = 0.01f; Vine3D_Grapevine::Vine3D_Grapevine() -{ -} - +{} bool Vine3D_Grapevine::compute(bool computeDaily, int secondsPerStep, Crit3DModelCase* modelCase, double chlorophyll) { @@ -106,18 +104,13 @@ bool Vine3D_Grapevine::compute(bool computeDaily, int secondsPerStep, Crit3DMode grassTranspiration(modelCase); return(true); - } + void Vine3D_Grapevine::resetLayers() { for (int i=0 ; i < nrMaxLayers ; i++) { - //psiSoilProfile[i] = NODATA ; - //soilWaterContentProfile[i]= NODATA ; - //soilWaterContentProfileFC[i]= NODATA; - //soilWaterContentProfileWP[i]= NODATA; - //soilFieldCapacity[i] = NODATA; fractionTranspirableSoilWaterProfile[i]= NODATA; stressCoefficientProfile[i] = NODATA; transpirationInstantLayer[i] = NODATA; @@ -126,15 +119,11 @@ void Vine3D_Grapevine::resetLayers() } } -bool Vine3D_Grapevine::initializeLayers(int myMaxLayers) + +void Vine3D_Grapevine::initializeLayers(int myMaxLayers) { nrMaxLayers = myMaxLayers; - //psiSoilProfile = (double *) calloc(nrLayers, sizeof(double)); - //soilWaterContentProfile = (double *) calloc(nrLayers, sizeof(double)); - //soilWaterContentProfileFC = (double *) calloc(nrLayers, sizeof(double)); - //soilWaterContentProfileWP = (double *) calloc(nrLayers, sizeof(double)); - //soilFieldCapacity = (double *) calloc (nrLayers, sizeof(double)); fractionTranspirableSoilWaterProfile = static_cast (calloc(size_t(nrMaxLayers), sizeof(double))); stressCoefficientProfile = static_cast (calloc(size_t(nrMaxLayers), sizeof(double))); transpirationInstantLayer = static_cast (calloc(size_t(nrMaxLayers), sizeof(double))); @@ -143,10 +132,9 @@ bool Vine3D_Grapevine::initializeLayers(int myMaxLayers) currentProfile = static_cast (calloc(size_t(nrMaxLayers), sizeof(double))); resetLayers(); - - return true; } + void Vine3D_Grapevine::setDate (Crit3DTime myTime) { myDoy = getDoyFromDate(myTime.date); @@ -167,22 +155,25 @@ bool Vine3D_Grapevine::setWeather(double meanDailyTemp, double temp, double irra myMeanDailyTemperature = meanDailyTemp; double deltaRelHum = MAXVALUE(100.0 - myRelativeHumidity, 0.01); myVaporPressureDeficit = 0.01 * deltaRelHum * 613.75 * exp(17.502 * myInstantTemp / (240.97 + myInstantTemp)); - //globalRadiation = globRad; - if ((int(prec) != NODATA) && (int(temp) != NODATA) && (int(windSpeed) != NODATA) && (int(irradiance) != NODATA) && (int(relativeHumidity) != NODATA) && (int(atmosphericPressure) != NODATA)) isReadingOK = true ; - return isReadingOK ; + + if ((int(prec) != NODATA) && (int(temp) != NODATA) && (int(windSpeed) != NODATA) + && (int(irradiance) != NODATA) && (int(relativeHumidity) != NODATA) && (int(atmosphericPressure) != NODATA)) + isReadingOK = true; + + return isReadingOK; } + bool Vine3D_Grapevine::setDerivedVariables(double diffuseIrradiance, double directIrradiance, double cloudIndex, double sunElevation) { bool isReadingOK = false; myDiffuseIrradiance = diffuseIrradiance ; myDirectIrradiance = directIrradiance ; - //myLongWaveIrradiance = longWaveIrradiance ; myCloudiness = MINVALUE(1,MAXVALUE(0,cloudIndex)) ; - //myAirVapourPressure = airVapourPressure ; mySunElevation = sunElevation; - if (int(sunElevation) != NODATA && int(diffuseIrradiance) != NODATA && int(directIrradiance) != NODATA - && int(cloudIndex) != NODATA) isReadingOK = true ; + if (int(sunElevation) != NODATA && int(diffuseIrradiance) != NODATA && int(directIrradiance) != NODATA && int(cloudIndex) != NODATA) + isReadingOK = true ; + return isReadingOK ; } @@ -196,32 +187,45 @@ void Vine3D_Grapevine::initializeWaterStress(Crit3DModelCase* modelCase) } -bool Vine3D_Grapevine::setSoilProfile(Crit3DModelCase* modelCase, double* myWiltingPoint, double* myFieldCapacity, - double* myPsiSoilProfile, double* mySoilWaterContentProfile, - double* mySoilWaterContentFC, double* mySoilWaterContentWP) +bool Vine3D_Grapevine::setSoilProfile(Crit3DModelCase* modelCase, std::vector& myWiltingPoint, std::vector& myFieldCapacity, + std::vector& myPsiSoilProfile, std::vector& mySoilWaterContentProfile, + std::vector& mySoilWaterContentFC, std::vector& mySoilWaterContentWP) { - double psiSoilProfile; - double logPsiSoilAverage = 0.; - double logPsiFCAverage = 0.; - double soilFieldCapacity; + // check last Soil layer + int lastLayer = modelCase->soilLayersNr - 1; + for (int i = 1; i < modelCase->soilLayersNr; i++) + { + if (isEqual(myPsiSoilProfile[i], NODATA) || isEqual(myFieldCapacity[i], NODATA) || isEqual(mySoilWaterContentProfile[i], NODATA) + || isEqual(mySoilWaterContentProfile[i], NODATA) || isEqual(mySoilWaterContentWP[i], NODATA)) + { + lastLayer = i-1; + break; + } + } + if (lastLayer == 0) + return false; psiSoilAverage = 0.; psiFieldCapacityAverage = 0.; - if (int(myWiltingPoint[int(modelCase->soilLayersNr / 2)]) == NODATA) - return false; + // initialize vector + for (int i = 1; i < modelCase->soilLayersNr; i++) + { + transpirationLayer[i] = 0.; + transpirationCumulatedGrass[i] = 0.; + fractionTranspirableSoilWaterProfile[i] = 0.; + } - wiltingPoint = myWiltingPoint[int(modelCase->soilLayersNr / 2)] / 101.97; // conversion from mH2O to MPa + int midLayer = (lastLayer + 1) / 2; + wiltingPoint = myWiltingPoint[midLayer] / 101.97; // conversion from mH2O to MPa //layer 0: surface, no soil - for (int i = 1; i < modelCase->soilLayersNr; i++) + double logPsiSoilAverage = 0.; + double logPsiFCAverage = 0.; + for (int i = 1; i <= lastLayer; i++) { - if (isEqual(myPsiSoilProfile[i], NODATA) || isEqual(myFieldCapacity[i], NODATA) || isEqual(mySoilWaterContentProfile[i], NODATA) - || isEqual(mySoilWaterContentProfile[i], NODATA) || isEqual(mySoilWaterContentWP[i], NODATA)) - return false; - - soilFieldCapacity = myFieldCapacity[i]/101.97; // conversion from mH2O to MPa - psiSoilProfile = MINVALUE(myPsiSoilProfile[i],-1.)/101.97 ; // conversion from mH2O to MPa + double soilFieldCapacity = myFieldCapacity[i] / 101.97; // conversion from mH2O to MPa + double psiSoilProfile = MINVALUE(myPsiSoilProfile[i], -1.) / 101.97 ; // conversion from mH2O to MPa logPsiSoilAverage += log(-psiSoilProfile) * modelCase->rootDensity[i]; logPsiFCAverage += log(-soilFieldCapacity) * modelCase->rootDensity[i]; } @@ -230,28 +234,26 @@ bool Vine3D_Grapevine::setSoilProfile(Crit3DModelCase* modelCase, double* myWilt psiFieldCapacityAverage = -exp(logPsiFCAverage); fractionTranspirableSoilWaterAverage = 0; - double waterContent, waterContentFC, waterContentWP; - - for (int i = 0; i < modelCase->soilLayersNr; i++) + for (int i = 0; i <= lastLayer; i++) { - waterContent = mySoilWaterContentProfile[i]; - waterContentFC = mySoilWaterContentFC[i]; - waterContentWP = mySoilWaterContentWP[i]; + double waterContent = mySoilWaterContentProfile[i]; + double waterContentFC = mySoilWaterContentFC[i]; + double waterContentWP = mySoilWaterContentWP[i]; fractionTranspirableSoilWaterProfile[i] = MAXVALUE(0, MINVALUE(1, (waterContent - waterContentWP) / (waterContentFC - waterContentWP))); fractionTranspirableSoilWaterAverage += fractionTranspirableSoilWaterProfile[i] * modelCase->rootDensity[i]; - transpirationLayer[i] = 0.; - transpirationCumulatedGrass[i] = 0. ; } + return true ; } -bool Vine3D_Grapevine::setStatePlant(TstatePlant myStatePlant, bool isVineyard) + +bool Vine3D_Grapevine::setStatePlant(TstatePlant myStatePlant, bool isVineyard_) { statePlant = myStatePlant; this->statePlant.outputPlant.transpirationNoStress = 0.; - if (! isVineyard) + if (! isVineyard_) { statePlant.outputPlant.brixBerry = NODATA; statePlant.statePheno.stage = NODATA; @@ -259,17 +261,8 @@ bool Vine3D_Grapevine::setStatePlant(TstatePlant myStatePlant, bool isVineyard) statePlant.stateGrowth.leafAreaIndex = NODATA; statePlant.stateGrowth.fruitBiomass = NODATA; } - return true; -} -TstatePlant Vine3D_Grapevine::getStatePlant() -{ - return(this->statePlant); -} - -ToutputPlant Vine3D_Grapevine::getOutputPlant() -{ - return (this->statePlant.outputPlant); + return true; } @@ -279,13 +272,13 @@ void Vine3D_Grapevine::getFixSimulationParameters() parameterBindiMigliettaFix.a = -0.28; parameterBindiMigliettaFix.b = 0.04; parameterBindiMigliettaFix.c = -0.015; - //parameterBindiMigliettaFix.baseTemperature = 10; - //parameterBindiMigliettaFix.tempMaxThreshold = 35; parameterBindiMigliettaFix.extinctionCoefficient = 0.5; parameterBindiMigliettaFix.shadedSurface = 0.8; + // Wang Leuning parameters parameterWangLeuningFix.stomatalConductanceMin = 0.008; parameterWangLeuningFix.optimalTemperatureForPhotosynthesis = 298.15; + // fenovitis parameters parameterPhenoVitisFix.a= 0.005; parameterPhenoVitisFix.optimalChillingTemp = 2.8; @@ -536,6 +529,8 @@ void Vine3D_Grapevine::radiationAbsorption() { sunlit.leafAreaIndex = 0.0 ; sunlit.absorbedPAR = 0.0 ; + + // TODO: non servono? sunlitAbsorbedNIR = 0.0 ; sunlitAbsorbedLW = 0.0 ; sunlit.isothermalNetRadiation = 0.0 ; @@ -548,12 +543,13 @@ void Vine3D_Grapevine::radiationAbsorption() shadedAbsorbedLW= dum[16] * (UPSCALINGFUNC(diffuseLightK,statePlant.stateGrowth.leafAreaIndex) - UPSCALINGFUNC(directLightK+diffuseLightK,statePlant.stateGrowth.leafAreaIndex)) ; shaded.isothermalNetRadiation = shaded.absorbedPAR + shadedAbsorbedNIR + shadedAbsorbedLW ; } + // Convert absorbed PAR into units of mol m-2 s-1 sunlit.absorbedPAR *= 4.57E-6 ; shaded.absorbedPAR *= 4.57E-6 ; - } + void Vine3D_Grapevine::leafTemperature() { // taken from Hydrall Model, Magnani UNIBO @@ -706,7 +702,8 @@ void Vine3D_Grapevine::aerodynamicalCoupling() { sunlitDeltaTemp = 0.0; } - sunlitDeltaTemp = 0.0; + sunlitDeltaTemp = 0.0; // TODO: check + sunlit.leafTemperature = myInstantTemp + sunlitDeltaTemp + ZEROCELSIUS ; //sunlit big-leaf stomatalConductanceWater = 10.0/shaded.leafAreaIndex ; //dummy stom res for shaded big-leaf //if (shaded.isothermalNetRadiation > 100) stomatalConductanceWater *= pow(100/shaded.isothermalNetRadiation,0.5); @@ -813,10 +810,9 @@ void Vine3D_Grapevine::upscale(TVineCultivar *cultivar) sunlit.darkRespiration = 0.0; sunlit.maximalCarboxylationRate = 0.0; } - - } + void Vine3D_Grapevine::photosynthesisKernel(TVineCultivar* cultivar, double COMP,double GAC,double GHR,double GSCD,double J,double KC,double KO ,double RD,double RNI,double STOMWL,double VCmax,double *ASS,double *GSC,double *TR) { diff --git a/agrolib/grapevine/grapevine.h b/agrolib/grapevine/grapevine.h index 7f773da6..1ff7442c 100644 --- a/agrolib/grapevine/grapevine.h +++ b/agrolib/grapevine/grapevine.h @@ -41,9 +41,9 @@ enum phenoStage {endoDormancy, ecoDormancy , budBurst , flowering , fruitSet, veraison, physiologicalMaturity, vineSenescence}; enum TfieldOperation {irrigationOperation, grassSowing, grassRemoving, trimming, leafRemoval, clusterThinning, harvesting, tartaricAnalysis}; - enum Crit3DLanduse {landuse_nodata, landuse_bare, landuse_vineyard}; + enum GrapevineLanduse {landuse_nodata, landuse_bare, landuse_vineyard}; - const std::map landuseNames = { + const std::map landuseNames = { { "UNDEFINED", landuse_nodata }, { "BARESOIL", landuse_bare }, { "VINEYARD", landuse_vineyard} @@ -191,14 +191,14 @@ struct Crit3DModelCase { int id; - Crit3DLanduse landuse; + GrapevineLanduse landuse; int soilIndex; float shootsPerPlant; float plantDensity; float maxLAIGrass; int trainingSystem; - float maxIrrigationRate; //[mm/h] + float maxIrrigationRate; // [mm h-1] int soilLayersNr; double soilTotalDepth; @@ -300,8 +300,7 @@ double psiSoilAverage; double psiFieldCapacityAverage; - //double* layerRootDensity; - double totalStomatalConductance, totalStomatalConductanceNoStress ; + double totalStomatalConductance, totalStomatalConductanceNoStress; double transpirationInstant; double* currentProfile; double* transpirationInstantLayer; //molH2O m^-2 s^-1 @@ -327,8 +326,6 @@ bool isAmphystomatic ; double specificLeafArea ; double alphaLeuning ; - //double leafNitrogen ; - //double entropicFactorCarboxyliation,entropicFactorElectronTransporRate ; Vine3D_SunShade shaded ; Vine3D_SunShade sunlit ; @@ -374,7 +371,7 @@ double getWaterStressByPsiSoil(double myPsiSoil,double psiSoilStressParameter,double exponentialFactorForPsiRatio); double getWaterStressSawFunction(int index, TVineCultivar *cultivar); - //bool getExtractedWaterFromGrassTranspirationandEvaporation(double* myWaterExtractionProfile); + double getWaterStressSawFunctionAverage(TVineCultivar* cultivar); double getGrassTranspiration(double stress, double laiGrassMax, double sensitivityToVPD, double fieldCoverByPlant); double getFallowTranspiration(double stress, double laiGrassMax, double sensitivityToVPD); @@ -392,8 +389,13 @@ public: Vine3D_Grapevine(); + TstatePlant getStatePlant(){ return statePlant; } + ToutputPlant getOutputPlant() { return statePlant.outputPlant; } + + bool setStatePlant(TstatePlant myStatePlant, bool isVineyard_); + //void initializeGrapevineModel(TVineCultivar* cultivar, double secondsPerStep); - bool initializeLayers(int myMaxLayers); + void initializeLayers(int myMaxLayers); bool initializeStatePlant(int doy, Crit3DModelCase *vineField); void resetLayers(); @@ -409,15 +411,12 @@ double prec , double relativeHumidity , double windSpeed, double atmosphericPressure); bool setDerivedVariables (double diffuseIrradiance, double directIrradiance, double cloudIndex, double sunElevation); - bool setSoilProfile(Crit3DModelCase *modelCase, double* myWiltingPoint, double *myFieldCapacity, - double *myPsiSoilProfile , double *mySoilWaterContentProfile, - double* mySoilWaterContentFC, double* mySoilWaterContentWP); - bool setStatePlant(TstatePlant myStatePlant, bool isVineyard); - TstatePlant getStatePlant(); - ToutputPlant getOutputPlant(); + bool setSoilProfile(Crit3DModelCase* modelCase, std::vector& myWiltingPoint, std::vector& myFieldCapacity, + std::vector& myPsiSoilProfile, std::vector& mySoilWaterContentProfile, + std::vector& mySoilWaterContentFC, std::vector& mySoilWaterContentWP); + double* getExtractedWater(Crit3DModelCase* modelCase); - //bool getOutputPlant(int hour, ToutputPlant *outputPlant); double getStressCoefficient(); double getRealTranspirationGrapevine(Crit3DModelCase *modelCase); double getRealTranspirationGrass(Crit3DModelCase *modelCase); diff --git a/agrolib/graphics/colorLegend.cpp b/agrolib/graphics/colorLegend.cpp index ef0f42ff..93c5a1fb 100644 --- a/agrolib/graphics/colorLegend.cpp +++ b/agrolib/graphics/colorLegend.cpp @@ -22,9 +22,12 @@ void ColorLegend::paintEvent(QPaintEvent *event) { Q_UNUSED(event) - if (this->colorScale == nullptr) return; + // check + if (this->colorScale == nullptr) + return; if (isEqual(this->colorScale->minimum(), NODATA) - || isEqual(this->colorScale->maximum(), NODATA)) return; + || isEqual(this->colorScale->maximum(), NODATA)) + return; QPainter painter(this); Crit3DColor* myColor; @@ -36,14 +39,14 @@ void ColorLegend::paintEvent(QPaintEvent *event) const int BLANK_DX = 16; int legendWidth = painter.window().width() - BLANK_DX*2; unsigned int nrStep = this->colorScale->nrColors(); - float step = (colorScale->maximum() - colorScale->minimum()) / float(nrStep); + double step = (colorScale->maximum() - colorScale->minimum()) / double(nrStep); double dx = double(legendWidth) / double(nrStep+1); unsigned int stepText = MAXVALUE(nrStep / 4, 1); QString valueStr; int nrDigits; double dblValue, shiftFatctor; - float value = this->colorScale->minimum(); + double value = this->colorScale->minimum(); for (unsigned int i = 0; i <= nrStep; i++) { dblValue = double(value); @@ -53,13 +56,13 @@ void ColorLegend::paintEvent(QPaintEvent *event) if ((i % stepText) == 0) { - if (isEqual(dblValue, 0)) + if (fabs(dblValue) <= 1) { nrDigits = 1; } else { - nrDigits = int(ceil(log10(abs(dblValue)))); + nrDigits = int(ceil(log10(fabs(dblValue)))); } // negative numbers diff --git a/agrolib/graphics/mapGraphicsRasterObject.cpp b/agrolib/graphics/mapGraphicsRasterObject.cpp index 051aab8f..ebabc397 100644 --- a/agrolib/graphics/mapGraphicsRasterObject.cpp +++ b/agrolib/graphics/mapGraphicsRasterObject.cpp @@ -1,7 +1,7 @@ /*! \file mapGraphicsRasterObject.cpp - \abstract draw raster in MapGraphics widget + \abstract draws a lat-lon raster in the MapGraphics widget This file is part of CRITERIA-3D distribution. @@ -73,16 +73,6 @@ void RasterObject::clear() } -void RasterObject::setRaster(gis::Crit3DRasterGrid* rasterPtr) -{ - rasterPointer = rasterPtr; -} - -gis::Crit3DRasterGrid* RasterObject::getRaster() -{ - return rasterPointer; -} - void RasterObject::setDrawing(bool value) { isDrawing = value; @@ -240,6 +230,7 @@ bool RasterObject::initializeUTM(gis::Crit3DRasterGrid* myRaster, const gis::Cri setDrawing(true); setDrawBorders(isGrid); + setVisible(true); isLoaded = true; return true; @@ -271,7 +262,8 @@ bool RasterObject::initializeLatLon(gis::Crit3DRasterGrid* myRaster, const gis:: } setDrawing(true); - setDrawBorders(isGrid_); + setDrawBorders(isGrid); + setVisible(true); isLoaded = true; return true; @@ -379,7 +371,7 @@ bool RasterObject::drawRaster(gis::Crit3DRasterGrid *myRaster, QPainter* myPaint } // dynamic color scale - if (! myRaster->colorScale->isRangeBlocked()) + if (! myRaster->colorScale->isFixedRange()) { if (this->isLatLon) { @@ -527,7 +519,7 @@ bool RasterObject::getRowCol(gis::Crit3DGeoPoint geoPoint, int* row, int* col) if (! this->isGrid) return false; - gis::getGridRowColFromXY(this->latLonHeader, geoPoint.longitude, geoPoint.latitude, row, col); + gis::getGridRowColFromLonLat(this->latLonHeader, geoPoint.longitude, geoPoint.latitude, row, col); // check out of grid if (gis::isOutOfGridRowCol(*row, *col, this->latLonHeader)) diff --git a/agrolib/graphics/mapGraphicsRasterObject.h b/agrolib/graphics/mapGraphicsRasterObject.h index bcfa7187..da44166f 100644 --- a/agrolib/graphics/mapGraphicsRasterObject.h +++ b/agrolib/graphics/mapGraphicsRasterObject.h @@ -79,8 +79,10 @@ const gis::Crit3DLatLonHeader& latLonHeader, bool isGrid_); float getRasterMaxSize(); gis::Crit3DGeoPoint* getRasterCenter(); - void setRaster(gis::Crit3DRasterGrid* rasterPtr); - gis::Crit3DRasterGrid* getRaster(); + + void setRaster(gis::Crit3DRasterGrid* rasterPtr) { rasterPointer = rasterPtr; } + gis::Crit3DRasterGrid* getRasterPointer() { return rasterPointer; } + void updateCenter(); Position getCurrentCenter(); diff --git a/agrolib/graphics/mapGraphicsRasterUtm.cpp b/agrolib/graphics/mapGraphicsRasterUtm.cpp index ca92733b..a8937d86 100644 --- a/agrolib/graphics/mapGraphicsRasterUtm.cpp +++ b/agrolib/graphics/mapGraphicsRasterUtm.cpp @@ -1,7 +1,7 @@ /*! - \file mapGraphicsRasterObject.cpp + \file mapGraphicsRasterUtm.cpp - \abstract draw raster in MapGraphics widget + \abstract draws a UTM raster in the MapGraphics widget This file is part of CRITERIA-3D distribution. @@ -29,6 +29,7 @@ #include "commonConstants.h" #include "mapGraphicsRasterUtm.h" #include "basicMath.h" +#include "color.h" #include #include @@ -326,7 +327,7 @@ bool RasterUtmObject::drawRaster(QPainter* painter) } // dynamic color scale - if (! _rasterPointer->colorScale->isRangeBlocked()) + if (! _rasterPointer->colorScale->isFixedRange()) { gis::updateColorScale(_rasterPointer, rasterWindow); roundColorScale(_rasterPointer->colorScale, 4, true); @@ -362,10 +363,17 @@ bool RasterUtmObject::drawRaster(QPainter* painter) // raster value float value = _rasterPointer->value[rowCenter][colCenter]; - // skip the NODATA value + // check NODATA value (transparent) if (isEqual(value, _rasterPointer->header->flag) || isEqual(value, NODATA)) continue; + // check outliers (transparent) + if (_rasterPointer->colorScale->isHideOutliers()) + { + if (value <= _rasterPointer->colorScale->minimum() || value > _rasterPointer->colorScale->maximum()) + continue; + } + // set color myColor = _rasterPointer->colorScale->getColor(value); myQColor = QColor(myColor->red, myColor->green, myColor->blue); diff --git a/agrolib/graphics/mapGraphicsRasterUtm.h b/agrolib/graphics/mapGraphicsRasterUtm.h index 2a67e962..ec679ef6 100644 --- a/agrolib/graphics/mapGraphicsRasterUtm.h +++ b/agrolib/graphics/mapGraphicsRasterUtm.h @@ -70,7 +70,7 @@ void setColorLegend(ColorLegend* colorLegendPtr) {_colorLegendPointer = colorLegendPtr;} void setRaster(gis::Crit3DRasterGrid* rasterPtr) {_rasterPointer = rasterPtr;} - gis::Crit3DRasterGrid* getRaster() {return _rasterPointer;} + gis::Crit3DRasterGrid* getRasterPointer() {return _rasterPointer;} float getValue(Position& pos); float getRasterMaxSize(); diff --git a/agrolib/graphics/squareMarker.cpp b/agrolib/graphics/squareMarker.cpp index 8545c5ea..a2581512 100644 --- a/agrolib/graphics/squareMarker.cpp +++ b/agrolib/graphics/squareMarker.cpp @@ -2,53 +2,25 @@ #include "squareMarker.h" -SquareMarker::SquareMarker(qreal side,bool sizeIsZoomInvariant, QColor fillColor, MapGraphicsObject *parent) : +SquareMarker::SquareMarker(qreal side, bool sizeIsZoomInvariant, QColor fillColor, MapGraphicsObject *parent) : SquareObject(side, sizeIsZoomInvariant, fillColor, parent) { - this->setFlag(MapGraphicsObject::ObjectIsSelectable, false); - this->setFlag(MapGraphicsObject::ObjectIsMovable, false); - this->setFlag(MapGraphicsObject::ObjectIsFocusable, false); + setFlag(MapGraphicsObject::ObjectIsSelectable, false); + setFlag(MapGraphicsObject::ObjectIsMovable, false); + setFlag(MapGraphicsObject::ObjectIsFocusable, false); - _id = ""; - _currentValue = NODATA; _active = true; } -void SquareMarker::setId(std::string id) -{ - _id = id; -} - -std::string SquareMarker::id() const -{ - return _id; -} - -void SquareMarker::setCurrentValue(float currentValue) -{ - _currentValue = currentValue; -} - -bool SquareMarker::active() const -{ - return _active; -} - -void SquareMarker::setActive(bool active) -{ - _active = active; -} void SquareMarker::setToolTip() { - QString idpoint = QString::fromStdString(_id); - QString toolTipText = QString("Point: %1
") - .arg(idpoint); + .arg(id()); - if (_currentValue != NODATA) + if (currentValue() != NODATA) { - QString value = QString::number(_currentValue); + QString value = QString::number(currentValue()); toolTipText += QString("value: %1 ").arg(value); } diff --git a/agrolib/graphics/squareMarker.h b/agrolib/graphics/squareMarker.h index 19d6959e..ca884df2 100644 --- a/agrolib/graphics/squareMarker.h +++ b/agrolib/graphics/squareMarker.h @@ -8,22 +8,17 @@ { Q_OBJECT + private: + bool _active; + public: explicit SquareMarker(qreal side, bool sizeIsZoomInvariant, QColor fillColor, MapGraphicsObject *parent = nullptr); - std::string id() const; - bool active() const; + bool active() const { return _active; } + void setActive(bool active) { _active = active; } - void setId(std::string id); - void setActive(bool active); - void setCurrentValue(float currentValue); void setToolTip(); - private: - std::string _id; - bool _active; - float _currentValue; - protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); diff --git a/agrolib/graphics/stationMarker.cpp b/agrolib/graphics/stationMarker.cpp index 233edb7d..7faae038 100644 --- a/agrolib/graphics/stationMarker.cpp +++ b/agrolib/graphics/stationMarker.cpp @@ -12,64 +12,18 @@ StationMarker::StationMarker(qreal radius,bool sizeIsZoomInvariant, QColor fillC this->setFlag(MapGraphicsObject::ObjectIsSelectable, false); this->setFlag(MapGraphicsObject::ObjectIsMovable, false); this->setFlag(MapGraphicsObject::ObjectIsFocusable, false); + _id = ""; _name = ""; _dataset = ""; + _municipality = ""; _altitude = NODATA; _lapseRateCode = primary; - _municipality = ""; - _active = true; -} - -void StationMarker::setId(std::string id) -{ - _id = id; -} - -std::string StationMarker::id() const -{ - return _id; -} - -void StationMarker::setName(const std::string &name) -{ - _name = name; -} - -void StationMarker::setDataset(const std::string &dataset) -{ - _dataset = dataset; -} - -void StationMarker::setAltitude(double altitude) -{ - _altitude = altitude; -} - -void StationMarker::setLapseRateCode(lapseRateCodeType code) -{ - _lapseRateCode = code; -} - -void StationMarker::setMunicipality(const std::string &municipality) -{ - _municipality = municipality; -} - -void StationMarker::setQuality(const quality::qualityType &quality) -{ - _quality = quality; -} -bool StationMarker::active() const -{ - return _active; + _caller = PRAGA_caller; + _active = true; } -void StationMarker::setActive(bool active) -{ - _active = active; -} void StationMarker::setToolTip() { @@ -109,74 +63,101 @@ void StationMarker::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::RightButton) { - bool isGrid = false; - QMenu menu; - QAction *openMeteoWidget = menu.addAction("Open new meteo widget"); - QAction *appendMeteoWidget = menu.addAction("Append to last meteo widget"); - menu.addSeparator(); - QAction *openPointStatisticsWidget = menu.addAction("Open point statistics widget"); - QAction *openHomogeneityWidget = menu.addAction("Open homogeneity test widget"); - menu.addSeparator(); - QAction *openSynchronicityWidget = menu.addAction("Open synchronicity test widget"); - QAction *setSynchronicityReferencePoint = menu.addAction("Set as synchronicity reference point"); - menu.addSeparator(); - QMenu *orogCodeSubMenu; - orogCodeSubMenu = menu.addMenu("Orog code"); - QAction *actionOrogCode_primary = orogCodeSubMenu->addAction( "Set as primary station" ); - QAction *actionOrogCode_secondary = orogCodeSubMenu->addAction( "Set as secondary station" ); - QAction *actionOrogCode_supplemental = orogCodeSubMenu->addAction( "Set as supplemental station" ); - menu.addSeparator(); - QAction *actionMarkPoint = menu.addAction( "Mark point" ); - QAction *actionUnmarkPoint = menu.addAction( "Unmark point" ); - - QAction *selection = menu.exec(QCursor::pos()); - - if (selection != nullptr) + if (_caller == PRAGA_caller) { - std::string lapseRateCode = getLapseRateCodeName(_lapseRateCode); - if (selection == openMeteoWidget) - { - emit newStationClicked(_id, _name, _dataset, _altitude, lapseRateCode, isGrid); - } - else if (selection == appendMeteoWidget) - { - emit appendStationClicked(_id, _name, _dataset, _altitude, lapseRateCode, isGrid); - } - else if (selection == openPointStatisticsWidget) - { - emit newPointStatisticsClicked(_id, isGrid); - } - else if (selection == openHomogeneityWidget) - { - emit newHomogeneityTestClicked(_id); - } - else if (selection == openSynchronicityWidget) - { - emit newSynchronicityTestClicked(_id); - } - else if (selection == setSynchronicityReferencePoint) - { - emit setSynchronicityReferenceClicked(_id); - } - else if (selection == actionOrogCode_primary) - { - emit changeOrogCodeClicked(_id, 0); - } - else if (selection == actionOrogCode_secondary) - { - emit changeOrogCodeClicked(_id, 1); - } - else if (selection == actionOrogCode_supplemental) + QMenu menu; + QAction *openMeteoWidget = menu.addAction("Open a new meteo widget"); + QAction *appendMeteoWidget = menu.addAction("Append to the lastest meteo widget"); + menu.addSeparator(); + QAction *openPointStatisticsWidget = menu.addAction("Open point statistics widget"); + QAction *openHomogeneityWidget = menu.addAction("Open homogeneity test widget"); + menu.addSeparator(); + QAction *openSynchronicityWidget = menu.addAction("Open synchronicity test widget"); + QAction *setSynchronicityReferencePoint = menu.addAction("Set as synchronicity reference point"); + menu.addSeparator(); + QAction *actionMarkPoint = menu.addAction( "Mark point" ); + QAction *actionUnmarkPoint = menu.addAction( "Unmark point" ); + menu.addSeparator(); + QMenu *orogCodeSubMenu; + orogCodeSubMenu = menu.addMenu("Orog code"); + QAction *actionOrogCode_primary = orogCodeSubMenu->addAction( "Set as primary station" ); + QAction *actionOrogCode_secondary = orogCodeSubMenu->addAction( "Set as secondary station" ); + QAction *actionOrogCode_supplemental = orogCodeSubMenu->addAction( "Set as supplemental station" ); + + QAction *selection = menu.exec(QCursor::pos()); + + if (selection != nullptr) { - emit changeOrogCodeClicked(_id, 2); + bool isGrid = false; + std::string lapseRateCode = getLapseRateCodeName(_lapseRateCode); + if (selection == openMeteoWidget) + { + emit newStationClicked(_id, _name, _dataset, _altitude, lapseRateCode, isGrid); + } + else if (selection == appendMeteoWidget) + { + emit appendStationClicked(_id, _name, _dataset, _altitude, lapseRateCode, isGrid); + } + else if (selection == openPointStatisticsWidget) + { + emit newPointStatisticsClicked(_id, isGrid); + } + else if (selection == openHomogeneityWidget) + { + emit newHomogeneityTestClicked(_id); + } + else if (selection == openSynchronicityWidget) + { + emit newSynchronicityTestClicked(_id); + } + else if (selection == setSynchronicityReferencePoint) + { + emit setSynchronicityReferenceClicked(_id); + } + else if (selection == actionOrogCode_primary) + { + emit changeOrogCodeClicked(_id, 0); + } + else if (selection == actionOrogCode_secondary) + { + emit changeOrogCodeClicked(_id, 1); + } + else if (selection == actionOrogCode_supplemental) + { + emit changeOrogCodeClicked(_id, 2); + } + else if (selection == actionMarkPoint) + { + emit markPoint(_id); + } + else if (selection == actionUnmarkPoint) + { + emit unmarkPoint(_id); + } } - else if (selection == actionMarkPoint) - { - emit markPoint(_id); - } - else if (selection == actionUnmarkPoint) + } + else + { + // Other Software + QMenu menu; + QAction *openMeteoWidget = menu.addAction("Open a new meteo widget"); + QAction *appendMeteoWidget = menu.addAction("Append to the lastest meteo widget"); + menu.addSeparator(); + + QAction *selection = menu.exec(QCursor::pos()); + + if (selection != nullptr) { - emit unmarkPoint(_id); + bool isGrid = false; + std::string lapseRateCode = getLapseRateCodeName(_lapseRateCode); + if (selection == openMeteoWidget) + { + emit newStationClicked(_id, _name, _dataset, _altitude, lapseRateCode, isGrid); + } + else if (selection == appendMeteoWidget) + { + emit appendStationClicked(_id, _name, _dataset, _altitude, lapseRateCode, isGrid); + } } } } diff --git a/agrolib/graphics/stationMarker.h b/agrolib/graphics/stationMarker.h index 84171b4f..c98841de 100644 --- a/agrolib/graphics/stationMarker.h +++ b/agrolib/graphics/stationMarker.h @@ -5,36 +5,58 @@ #include "CircleObject.h" #include "MapGraphicsView.h" #include "quality.h" + #include "meteo.h" class Crit3DMeteoPoint; + enum callerSoftware{PRAGA_caller, CRITERIA3D_caller, other_caller}; + class StationMarker : public CircleObject { Q_OBJECT public: explicit StationMarker(qreal radius, bool sizeIsZoomInvariant, QColor fillColor, MapGraphicsObject *parent = nullptr); - void setId(std::string id); + void setToolTip(); - std::string id() const; - void setName(const std::string &name); - void setDataset(const std::string &dataset); - void setAltitude(double altitude); - void setLapseRateCode(lapseRateCodeType code); - void setMunicipality(const std::string &municipality); - void setQuality(const quality::qualityType &quality); - bool active() const; - void setActive(bool active); + + void setId(std::string id) { _id = id; } + std::string id() const { return _id; } + + bool active() const { return _active; } + void setActive(bool active) { _active = active; } + + void setName(const std::string &name) { _name = name; } + + void setDataset(const std::string &dataset) { _dataset = dataset; } + + void setAltitude(double altitude) { _altitude = altitude; } + + void setCallerSoftware(callerSoftware caller) + { _caller = caller;} + + void setLapseRateCode(lapseRateCodeType code) + { _lapseRateCode = code; } + + void setMunicipality(const std::string &municipality) + { _municipality = municipality; } + + void setQuality(const quality::qualityType &quality) + { _quality = quality; } private: std::string _id; std::string _name; std::string _dataset; - double _altitude; - lapseRateCodeType _lapseRateCode; std::string _municipality; + + double _altitude; float _currentValue; + + lapseRateCodeType _lapseRateCode; quality::qualityType _quality; + callerSoftware _caller; + bool _active; protected: diff --git a/agrolib/homogeneityWidget/annualSeriesChartView.cpp b/agrolib/homogeneityWidget/annualSeriesChartView.cpp index 096fb2dd..8332c69c 100644 --- a/agrolib/homogeneityWidget/annualSeriesChartView.cpp +++ b/agrolib/homogeneityWidget/annualSeriesChartView.cpp @@ -62,7 +62,7 @@ void AnnualSeriesChartView::draw(std::vector years, std::vector outp axisY->setMin(minValue-3); } axisX->setRange(years[0], years[years.size()-1]); - int nYears = years.size(); + int nYears = int(years.size()); if ( nYears <= 15) { axisX->setTickCount(nYears); diff --git a/agrolib/homogeneityWidget/homogeneityChartView.cpp b/agrolib/homogeneityWidget/homogeneityChartView.cpp index f9380be1..876ad56f 100644 --- a/agrolib/homogeneityWidget/homogeneityChartView.cpp +++ b/agrolib/homogeneityWidget/homogeneityChartView.cpp @@ -94,7 +94,7 @@ void HomogeneityChartView::drawSNHT(std::vector years, std::vector axisY->setMin(minValue-3); } axisX->setRange(years[0], years[years.size()-1]); - int nYears = years.size(); + int nYears = int(years.size()); if ( nYears <= 15) { axisX->setTickCount(nYears); diff --git a/agrolib/homogeneityWidget/homogeneityWidget.cpp b/agrolib/homogeneityWidget/homogeneityWidget.cpp index 7fdc71b6..1a56cc68 100644 --- a/agrolib/homogeneityWidget/homogeneityWidget.cpp +++ b/agrolib/homogeneityWidget/homogeneityWidget.cpp @@ -565,7 +565,7 @@ void Crit3DHomogeneityWidget::updateYears() void Crit3DHomogeneityWidget::on_actionChangeLeftAxis() { - DialogChangeAxis changeAxisDialog(true); + DialogChangeAxis changeAxisDialog(1, false); if (changeAxisDialog.result() == QDialog::Accepted) { homogeneityChartView->setYmax(changeAxisDialog.getMaxVal()); @@ -1060,7 +1060,7 @@ void Crit3DHomogeneityWidget::executeClicked() myValidValues.push_back((double)myAnnualSeries[i]); } } - double myAverage = statistics::mean(myValidValues, int(myValidValues.size())); + double myAverage = statistics::mean(myValidValues); std::vector myRefAverage; std::vector r2; std::vector> refSeriesVector; @@ -1079,7 +1079,7 @@ void Crit3DHomogeneityWidget::executeClicked() myRefValidValues.push_back((double)refSeries[i]); } } - myRefAverage.push_back(statistics::mean(myRefValidValues, int(myRefValidValues.size()))); + myRefAverage.push_back(statistics::mean(myRefValidValues)); statistics::linearRegression(myAnnualSeries, refSeries, long(myAnnualSeries.size()), false, &y_intercept, &trend, &r2Value); r2.push_back(r2Value); } @@ -1148,7 +1148,7 @@ void Crit3DHomogeneityWidget::executeClicked() myValidValues.push_back(myQ[i]); } } - double myQAverage = statistics::mean(myValidValues, int(myValidValues.size())); + double myQAverage = statistics::mean(myValidValues); double myQDevStd = statistics::standardDeviation(myValidValues, int(myValidValues.size())); std::vector myZ; for (int i = 0; i z1; @@ -1205,7 +1205,7 @@ void Crit3DHomogeneityWidget::executeClicked() myValidValues.push_back(z1[i]); } } - double myZ1Average = statistics::mean(myValidValues, int(myValidValues.size())); + double myZ1Average = statistics::mean(myValidValues); myValidValues.clear(); for (int i = 0; ixmlFileName = xmlFileName; this->meteoPointsDbHandler = meteoPointsDbHandler; this->meteoGridDbHandler = meteoGridDbHandler; - this->format_headerRow = 0; + this->nrHeaderRows = 0; } bool InOutDataXML::parseXMLFile(QDomDocument* xmlDoc, QString *errorStr) @@ -93,7 +93,7 @@ bool InOutDataXML::parserXML(QString *myError) } else if (mySecondTag == "NRCHAR" || mySecondTag == "NR_CHAR") { - fileName_nrChar = secondChild.toElement().text().toInt(); + nrFileNameChars = secondChild.toElement().text().toInt(); } secondChild = secondChild.nextSibling(); } @@ -124,26 +124,26 @@ bool InOutDataXML::parserXML(QString *myError) { if (child.toElement().text().toUpper().simplified() == "SINGLEPOINT") { - format_isSinglePoint = true; + isSinglePoint = true; } else { - format_isSinglePoint = false; + isSinglePoint = false; } } else if (myTag == "HEADER" || myTag == "HEADERROWS" || myTag == "NUMHEADERROWS") { - format_headerRow = child.toElement().text().toInt(); + nrHeaderRows = child.toElement().text().toInt(); } else if (myTag == "MISSINGVALUE" || myTag == "MISSING_VALUE" || myTag == "NODATA") { - format_missingValue = child.toElement().text().toFloat(); + missingValue = child.toElement().text().toFloat(); } else if (myTag == "DELIMITER") { if (child.toElement().text() == "") { - format_delimiter = " "; + format_delimiter = ","; } else { @@ -285,13 +285,13 @@ bool InOutDataXML::parserXML(QString *myError) VariableXML var; variable.push_back(var); child = ancestor.firstChild(); - while( !child.isNull()) + while(! child.isNull()) { myTag = child.toElement().tagName().toUpper(); if (myTag == "FIELD") { secondChild = child.firstChild(); - while( !secondChild.isNull()) + while(! secondChild.isNull()) { mySecondTag = secondChild.toElement().tagName().toUpper(); if (mySecondTag == "TYPE" || mySecondTag == "NAME") @@ -394,29 +394,6 @@ bool InOutDataXML::parserXML(QString *myError) } xmlDoc.clear(); - if (variableCode.getType().toUpper() == "FIXED") - { - for (int i = 0; i 1) - { - numVarFields = numVarFields + variable[i].nReplication; - } - else - { - numVarFields = numVarFields + 1; - } - } - } - else if (variable.size() > 0) - { - numVarFields = 1; - } - else - { - *myError = "Error in XML File: missing variables definition."; - return false; - } return true; } @@ -445,7 +422,7 @@ bool InOutDataXML::checkPointCodeFromFileName(QString& myPointCode, QString& err { myPointCode = ""; - if (! format_isSinglePoint) + if (! isSinglePoint) { errorStr = "Not singlePoint format."; return true; @@ -499,7 +476,7 @@ bool InOutDataXML::importXMLDataFixed(QString& errorStr) QString myPointCode = ""; QString previousPointCode = ""; - if (format_isSinglePoint) + if (isSinglePoint) { if (! checkPointCodeFromFileName(myPointCode, errorStr)) { @@ -516,12 +493,12 @@ bool InOutDataXML::importXMLDataFixed(QString& errorStr) int currentRow = 0; int nrErrors = 0; - while (!in.atEnd()) + while (! in.atEnd()) { QString line = in.readLine(); - if (currentRow >= format_headerRow && !line.isEmpty()) + if (currentRow >= nrHeaderRows && !line.isEmpty()) { - if (!format_isSinglePoint) + if (! isSinglePoint) { // multipoint myPointCode = parseXMLPointCode(line); @@ -564,9 +541,9 @@ bool InOutDataXML::importXMLDataFixed(QString& errorStr) if (time.getType().toUpper() == "DAILY") { QDate myDate = parseXMLDate(line); - if (!myDate.isValid() || myDate.year() == 1800) + if (! myDate.isValid() || myDate.year() == 1800) { - errorStr = "Date not found or not valid for file: " + dataFileName; + errorStr = "Date not found or invalid in file:\n" + dataFileName; return false; } for (int i = 0; i= format_headerRow && !line.isEmpty()) + if (currentRow >= nrHeaderRows && !line.isEmpty()) { - if (! format_isSinglePoint) + if (! isSinglePoint) { QList myFields = line.split(format_delimiter); @@ -876,14 +853,20 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) QList myFields = line.split(format_delimiter); QDate myDate(1800,1,1); + if (time.getPosition() <= 0) + { + errorStr = "Wrong Time field position (the number of fields must start from 1): " + QString::number(time.getPosition()); + return false; + } + if (time.getPosition()-1 < myFields.size()) { myDate = parseXMLDate(myFields[time.getPosition()-1]); } - if (!myDate.isValid() || myDate.year() == 1800) + if (! myDate.isValid() || myDate.year() == 1800) { - errorStr = "Date not found or not valid for file: " + dataFileName; + errorStr = "Date not found or invalid in file:\n" + dataFileName; return false; } @@ -897,7 +880,7 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) { int nReplication = 0; - if (!variable[i].flagAccepted.isEmpty() && variable[i].flagField.getPosition()>0 && variable[i].flagField.getPosition()-1 < myFields.size()) + if (! variable[i].flagAccepted.isEmpty() && variable[i].flagField.getPosition()>0 && variable[i].flagField.getPosition()-1 < myFields.size()) { if (variable[i].varField.getPosition() > 0 && variable[i].varField.getPosition()-1 < myFields.size()) { @@ -905,19 +888,19 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) if (myValue.toString() == "ERROR") { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; } } else { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; return false; } // check FLAG if (myFields[variable[i].flagField.getPosition()-1] != variable[i].flagAccepted) { - myValue = format_missingValue; + myValue = missingValue; } } else @@ -928,17 +911,17 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) if (myValue.toString() == "ERROR") { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; } } else { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; return false; } } - if (myValue != format_missingValue && myValue != NODATA) + if (myValue != missingValue && myValue != NODATA) { // write value meteoVariable var = getKeyMeteoVarMeteoMap(MapDailyMeteoVarToString, variable[i].varField.getType().toStdString()); @@ -980,9 +963,9 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) myDateTime = parseXMLDateTime(myFields[time.getPosition()-1]); } - if (!myDateTime.isValid() || myDateTime.date().year() == 1800) + if (! myDateTime.isValid() || myDateTime.date().year() == 1800) { - errorStr = "Date not found or not valid for file: " + dataFileName + "\n" + line; + errorStr = "Date not found or invalid in file:\n" + dataFileName + "\n" + line; return false; } @@ -1004,19 +987,19 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) if (myValue.toString() == "ERROR") { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; } } else { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; return false; } // check FLAG if (myFields[variable[i].flagField.getPosition()-1] != variable[i].flagAccepted) { - myValue = format_missingValue; + myValue = missingValue; } } else @@ -1027,17 +1010,17 @@ bool InOutDataXML::importXMLDataDelimited(QString& errorStr) if (myValue.toString() == "ERROR") { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; } } else { nrErrors++; - myValue = format_missingValue; + myValue = missingValue; return false; } } - if (myValue != format_missingValue && myValue != NODATA) + if (myValue != missingValue && myValue != NODATA) { // write myValue meteoVariable var = getKeyMeteoVarMeteoMap(MapHourlyMeteoVarToString, variable[i].varField.getType().toStdString()); @@ -1172,11 +1155,11 @@ QString InOutDataXML::parseXMLPointCode(QString text) { // con questa casistica l'import funziona anche con gli xml di export che hanno il campo filename e prefissi o suffissi nel nome del file QString substring = text; - for (int i = 0; i fileName_nrChar) + if (code.length() > nrFileNameChars) { return filename; } @@ -1388,7 +1371,7 @@ int InOutDataXML::getVariableFlagFirstChar() float InOutDataXML::getFormatMissingValue() { - return format_missingValue; + return missingValue; } diff --git a/agrolib/inOutDataXML/inOutDataXML.h b/agrolib/inOutDataXML/inOutDataXML.h index 9037b716..2c53e0ca 100644 --- a/agrolib/inOutDataXML/inOutDataXML.h +++ b/agrolib/inOutDataXML/inOutDataXML.h @@ -19,7 +19,9 @@ enum formatType{ XMLFORMATFIXED, XMLFORMATDELIMITED}; class InOutDataXML { public: - InOutDataXML(bool isGrid, Crit3DMeteoPointsDbHandler* meteoPointsDbHandler, Crit3DMeteoGridDbHandler* meteoGridDbHandler, QString xmlFileName); + InOutDataXML(bool isGrid, Crit3DMeteoPointsDbHandler* meteoPointsDbHandler, + Crit3DMeteoGridDbHandler* meteoGridDbHandler, QString xmlFileName); + bool parseXMLFile(QDomDocument* xmlDoc, QString *error); bool parserXML(QString *error); bool importDataMain(QString fileName, QString &error); @@ -50,26 +52,31 @@ class InOutDataXML private: bool isGrid; + bool isSinglePoint; + formatType format_type; + + int nrHeaderRows; + int nrFileNameChars; + float missingValue; + Crit3DMeteoPointsDbHandler* meteoPointsDbHandler; Crit3DMeteoGridDbHandler* meteoGridDbHandler; + QString xmlFileName; - bool format_isSinglePoint; - formatType format_type; - int format_headerRow; - float format_missingValue; + QString dataFileName; QString format_delimiter; QString format_decimalSeparator; QString fileName_path; QString fileName_pragaName; + QList fileName_fixedPrefix; QList fileName_fixedSuffix; - int fileName_nrChar; + FieldXML time; FieldXML pointCode; FieldXML variableCode; + QList variable; - QString dataFileName; - int numVarFields; }; #endif // INOUTDATAXML_H diff --git a/agrolib/interpolation/interpolation.cpp b/agrolib/interpolation/interpolation.cpp index 089ef9f8..a7651901 100644 --- a/agrolib/interpolation/interpolation.cpp +++ b/agrolib/interpolation/interpolation.cpp @@ -933,7 +933,7 @@ float modifiedShepardIdw(vector &myPoints, { t[i] = 0; for (j=0; j < validPoints.size(); j++) - if (i != j && S[i] > 0) + if (i != j && S[i] > 0 && validPoints[i].distance > 0 && validPoints[j].distance > 0) { cosine = ((X - (float)validPoints[i].point->utm.x) * (X - (float)validPoints[j].point->utm.x) + (Y - (float)validPoints[i].point->utm.y) * (Y - (float)validPoints[j].point->utm.y)) / (validPoints[i].distance * validPoints[j].distance); t[i] = t[i] + S[j] * (1 - cosine); @@ -1015,12 +1015,73 @@ float gaussWeighted(vector &myPointList) } */ +void localSelection_new(std::vector &inputPoints, std::vector &selectedPoints, + float x, float y, float z, Crit3DInterpolationSettings& mySettings) +{ + std::vector tempPoints; + unsigned int i; + float radius; + unsigned int nrValid = 0; + unsigned int minPoints = unsigned(mySettings.getMinPointsLocalDetrending() * 1.2); + float shepardInitialRadius = computeShepardInitialRadius(mySettings.getPointsBoundingBoxArea(), unsigned(inputPoints.size()), minPoints); + + // define a first neighborhood inside initial radius + for (i=0; i < inputPoints.size(); i++) + { + inputPoints[i].distance = gis::computeDistance(x, y, float((inputPoints[i]).point->utm.x), float((inputPoints[i]).point->utm.y)); + if (inputPoints[i].distance <= shepardInitialRadius && + inputPoints[i].distance > 0 && + checkLapseRateCode(inputPoints[i].lapseRateCode, mySettings.getUseLapseRateCode(), true)) + { + tempPoints.push_back(inputPoints[i]); + nrValid++; + } + } + + if (tempPoints.size() <= minPoints) + { + nrValid = sortPointsByDistance(minPoints + 1, inputPoints, selectedPoints); + if (nrValid > minPoints) + { + radius = selectedPoints[minPoints].distance; + selectedPoints.pop_back(); + } + else + radius = selectedPoints[nrValid-1].distance + float(EPSILON); + } + else if (tempPoints.size() > minPoints) + { + nrValid = sortPointsByDistance(minPoints + 1, tempPoints, selectedPoints); + radius = selectedPoints[minPoints].distance; + selectedPoints.pop_back(); + } + else + { + selectedPoints = tempPoints; + radius = shepardInitialRadius; + } + + for (int i = 0; i < selectedPoints.size(); i++) + { + selectedPoints[i].regressionWeight = MAXVALUE((-(1/std::pow(radius,4)*(std::pow(selectedPoints[i].distance,4)))+1),EPSILON); + //selectedPoints[i].regressionWeight = 1; + //selectedPoints[i].heightWeight = 1./((2./maxHeightDelta)*selectedPoints[i].point->z+1); + selectedPoints[i].heightWeight = 1; + } + mySettings.setLocalRadius(float(radius)); + + return; +} + + + + // TODO elevation std dev? void localSelection(vector &inputPoints, vector &selectedPoints, - float x, float y, Crit3DInterpolationSettings& mySettings) + float x, float y, float z, Crit3DInterpolationSettings& mySettings) { // search more stations to assure min points with all valid proxies - float ratioMinPoints = float(1.4); + float ratioMinPoints = float(1.3); unsigned minPoints = unsigned(mySettings.getMinPointsLocalDetrending() * ratioMinPoints); if (inputPoints.size() <= minPoints) { @@ -1033,13 +1094,15 @@ void localSelection(vector &inputPoints, vector < inputPoints[i].distance = gis::computeDistance(x, y, float((inputPoints[i]).point->utm.x), float((inputPoints[i]).point->utm.y)); unsigned int nrValid = 0; - float stepRadius = 5000; // [m] + float stepRadius = 2500; // [m] float r0 = 0; // [m] float r1 = stepRadius; // [m] unsigned int i; + unsigned int nrPrimaries = 0; - float maxDistance = 0; - while (nrValid < minPoints) + int maxDistance = 0; + float maxHeightDelta = 0; + while (nrValid < minPoints || (mySettings.getUseLapseRateCode() && nrPrimaries < minPoints)) { maxDistance = 0; for (i=0; i < inputPoints.size(); i++) @@ -1049,33 +1112,32 @@ void localSelection(vector &inputPoints, vector < selectedPoints.push_back(inputPoints[i]); nrValid++; if (inputPoints[i].distance > maxDistance) - maxDistance = inputPoints[i].distance; + maxDistance = int(inputPoints[i].distance); + + if (checkLapseRateCode(inputPoints[i].lapseRateCode, mySettings.getUseLapseRateCode(), true)) + nrPrimaries++; + + if (abs(inputPoints[i].point->z - z) > maxHeightDelta) + maxHeightDelta = fabs(float(inputPoints[i].point->z) - z); } } r0 = r1; r1 += stepRadius; } - /* //same number of stations for all cells - unsigned newIndex = selectedPoints.size(); - std::vector outputPoints; - if (nrValid > minPoints+1) - { - newIndex = sortPointsByDistance(minPoints + 1, selectedPoints, outputPoints); - while (outputPoints.size() > minPoints+1) - outputPoints.pop_back(); - } - selectedPoints.clear(); - selectedPoints = outputPoints; -*/ - - for (i=0; i< selectedPoints.size(); i++) - selectedPoints[i].regressionWeight = (1 - selectedPoints[i].distance / maxDistance); - - mySettings.setLocalRadius(maxDistance); + if (maxDistance != 0 && maxHeightDelta != 0) + for (i=0; i< selectedPoints.size(); i++) + { + //selectedPoints[i].regressionWeight = MAXVALUE(1 - selectedPoints[i].distance / (std::pow(maxDistance, 16.0/15.0)), EPSILON); + //selectedPoints[i].regressionWeight = MAXVALUE(std::exp(-std::pow(selectedPoints[i].distance/((4/5*maxDistance)),7.0)),EPSILON); + selectedPoints[i].regressionWeight = MAXVALUE((-(1/std::pow(maxDistance,4)*(std::pow(selectedPoints[i].distance,4)))+1),EPSILON); + //selectedPoints[i].regressionWeight = 1; + //selectedPoints[i].heightWeight = 1./((2./maxHeightDelta)*selectedPoints[i].point->z+1); + selectedPoints[i].heightWeight = 1; + } + mySettings.setLocalRadius(float(maxDistance)); } - bool checkPrecipitationZero(const std::vector &myPoints, float precThreshold, int &nrNotNull) { nrNotNull = 0; @@ -1098,6 +1160,7 @@ bool isThermal(meteoVariable myVar) myVar == dailyAirTemperatureAvg || myVar == dailyAirTemperatureMax || myVar == dailyAirTemperatureMin || + myVar == dailyReferenceEvapotranspirationHS || myVar == elaboration ) return true; else @@ -1112,6 +1175,7 @@ bool getUseDetrendingVar(meteoVariable myVar) myVar == dailyAirTemperatureAvg || myVar == dailyAirTemperatureMax || myVar == dailyAirTemperatureMin || + myVar == dailyReferenceEvapotranspirationHS || myVar == elaboration ) return true; @@ -1188,36 +1252,34 @@ void detrendPoints(std::vector &myPoints, Crit3DI float retrend(meteoVariable myVar, vector myProxyValues, Crit3DInterpolationSettings* mySettings) { - if (! getUseDetrendingVar(myVar)) return 0.; double retrendValue = 0.; double myProxyValue; Crit3DProxy* myProxy = nullptr; - Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); float proxySlope; + Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); if (mySettings->getUseMultipleDetrending()) { std::vector activeProxyValues; - if (getActiveProxyValues(mySettings, myProxyValues, activeProxyValues)) + if (getActiveProxyValues(myCombination, myProxyValues, activeProxyValues)) { - std::vector&)>> myFunc = mySettings->getFittingFunction(); + std::vector&)>> fullFunc = mySettings->getFittingFunction(); std::vector > fittingParameters = mySettings->getFittingParameters(); + removeEmptyFittingParameters(fittingParameters); - if (myFunc.size() > 0 && fittingParameters.size() > 0) - retrendValue = float(functionSum(myFunc, activeProxyValues, fittingParameters)); + std::vector&)>> myFunc; - for (int pos=0; pos < int(mySettings->getProxyNr()); pos++) //can be skipped if altitude is always first proxy - { - if (getProxyPragaName(mySettings->getProxy(pos)->getName()) == proxyHeight) - { - if (!mySettings->getProxy(pos)->getIsSignificant()) - retrendValue = 0.; - break; + for (const auto& function : fullFunc) { + if (function) { + myFunc.push_back(function); } } + + if (myFunc.size() > 0 && fittingParameters.size() > 0) + retrendValue = float(functionSum(myFunc, activeProxyValues, fittingParameters)); } } else @@ -1284,6 +1346,7 @@ bool regressionOrography(std::vector &myPoints, } } + void detrending(std::vector &myPoints, Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings, Crit3DClimateParameters* myClimate, meteoVariable myVar, Crit3DTime myTime) @@ -1360,64 +1423,128 @@ bool proxyValidity(std::vector &myPoints, int pro return true; } -bool setAllFittingRanges(Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings) +bool proxyValidityWeighted(std::vector &myPoints, int proxyPos, float stdDevThreshold, double &avg, double &stdDev) +{ + std::vector proxyValues; + const int MIN_NR = 10; + + std::vector data, weights; + data.resize(myPoints.size()); + weights.resize(myPoints.size()); + + for (int i = 0; i < myPoints.size(); i++) + { + data[i] = myPoints[i].getProxyValue(proxyPos); + weights[i] = myPoints[i].regressionWeight; + } + + + if (data.size() <= 0) { + // Handle the case when there is no data or weights + return 0.0; + } + + double sum_weights = 0.0; + double sum_weighted_data = 0.0; + double sum_squared_weighted_data = 0.0; + + // Calculate the necessary sums for weighted variance calculation + for (int i = 0; i < int(data.size()); i++) + { + sum_weights += weights[i]; + sum_weighted_data += data[i] * weights[i]; + sum_squared_weighted_data += data[i] * data[i] * weights[i]; + } + + // Calculate the weighted variance + double weighted_mean = sum_weighted_data / sum_weights; + double variance = (sum_squared_weighted_data / sum_weights) - (weighted_mean * weighted_mean); + + stdDev = sqrt(variance); + + if (stdDevThreshold != NODATA) + return (stdDev > stdDevThreshold); + else + return true; +} + +bool setHeightFittingRange(Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings) { if (mySettings->getMinMaxTemperature().empty()) return 0; + const double H0_MIN = -200; //height of inversion point (double piecewise) or first inversion point (triple piecewise) + const double H0_MAX = 5000; + const double DELTA_MIN = 300; //height difference between inversion points (for triple piecewise only) + const double DELTA_MAX = 1000; + const double SLOPE_MIN = 0.002; //ascending slope + const double SLOPE_MAX = 0.007; + const double INVSLOPE_MIN = -0.01; //inversion slope + const double INVSLOPE_MAX = -0.0015; + for (unsigned i=0; i < myCombination.getProxySize(); i++) if (myCombination.isProxyActive(i) == true) { if (getProxyPragaName(mySettings->getProxy(i)->getName()) == proxyHeight) { - double min = mySettings->getMinMaxTemperature()[0]; - double max = mySettings->getMinMaxTemperature()[1]; - std::vector tempParam; - if (mySettings->getChosenElevationFunction() == frei) - { - mySettings->getProxy(i)->setFittingFunctionName(frei); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {min, 0, -4, -200, 0.1, max+10, 0.006, 4, 1800, 1000}; - } - else if (mySettings->getChosenElevationFunction() == piecewiseTwo) - { - mySettings->getProxy(i)->setFittingFunctionName(piecewiseTwo); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {-200, min-2, 0, -0.006, 1800, max+2, 0.01, 0}; - } - else if (mySettings->getChosenElevationFunction() == piecewiseThree) - { - mySettings->getProxy(i)->setFittingFunctionName(piecewiseThree); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {-200, min-2, 100, 0, -0.006, 1800, max+2, 1000, (max-min-2), 0}; - } - else if (mySettings->getChosenElevationFunction() == piecewiseThreeFree) + const double MIN_T = mySettings->getMinMaxTemperature()[0]; + const double MAX_T = mySettings->getMinMaxTemperature()[1]; + + /* + * following line allows to check if the function for elevation has been changed (GUI only) compared to the + * function read in the .ini file. if it hasn't been changed, only the minimum and maximum temperature get rewritten. + * otherwise appropriate parameters are loaded into the proxy (fittingParametersRange) + */ + if (mySettings->getChosenElevationFunction() == mySettings->getProxy(i)->getFittingFunctionName()) { - mySettings->getProxy(i)->setFittingFunctionName(piecewiseThreeFree); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {-200, min-2, 100, 0.001, -0.006, -0.006, 1800, max+2, 1000, 0.007, 0, 0}; - } - else if (mySettings->getChosenElevationFunction() == piecewiseThreeSlope) - { - mySettings->getProxy(i)->setFittingFunctionName(piecewiseThreeSlope); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {-200, min-2, 100, 0.001, -0.006, 1800, max+2, 1000, 0.007, 0}; + std::vector tempParam; + tempParam = mySettings->getProxy(i)->getFittingParametersRange(); + if (!tempParam.empty()) + { + if (mySettings->getChosenElevationFunction() == piecewiseTwo) + { + tempParam[1] = MIN_T-2; + tempParam[5] = MAX_T+2; + } + else if (mySettings->getChosenElevationFunction() == piecewiseThreeFree) + { + tempParam[1] = MIN_T-2; + tempParam[7] = MAX_T+2; + } + else if (mySettings->getChosenElevationFunction() == piecewiseThree) + { + tempParam[1] = MIN_T-2; + tempParam[6] = MAX_T+2; + } + mySettings->getProxy(i)->setFittingParametersRange(tempParam); + } } - else if (mySettings->getChosenElevationFunction() == freiFree) + else { - mySettings->getProxy(i)->setFittingFunctionName(freiFree); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {min, 0, -4, -200, 0.1, 0, max+10, 0.006, 4, 1800, 1000, 0.006}; + std::vector tempParam; + if (mySettings->getChosenElevationFunction() == piecewiseTwo) + { + mySettings->getProxy(i)->setFittingFunctionName(piecewiseTwo); + tempParam = {H0_MIN, MIN_T-2, SLOPE_MIN, INVSLOPE_MIN, + H0_MAX, MAX_T+2, SLOPE_MAX, INVSLOPE_MAX}; + } + else if (mySettings->getChosenElevationFunction() == piecewiseThreeFree) + { + mySettings->getProxy(i)->setFittingFunctionName(piecewiseThreeFree); + tempParam = {H0_MIN, MIN_T-2, DELTA_MIN, SLOPE_MIN, INVSLOPE_MIN, INVSLOPE_MIN, + H0_MAX, MAX_T+2, DELTA_MAX, SLOPE_MAX, INVSLOPE_MAX, INVSLOPE_MAX}; + } + else if (mySettings->getChosenElevationFunction() == piecewiseThree) + { + mySettings->getProxy(i)->setFittingFunctionName(piecewiseThree); + tempParam = {H0_MIN, MIN_T-2, DELTA_MIN, SLOPE_MIN, INVSLOPE_MIN, + H0_MAX, MAX_T+2, DELTA_MAX, SLOPE_MAX, INVSLOPE_MAX}; + } + mySettings->getProxy(i)->setFittingParametersRange(tempParam); } - mySettings->getProxy(i)->setFittingParametersRange(tempParam); - } - else - { - mySettings->getProxy(i)->setFittingFunctionName(linear); - mySettings->getProxy(i)->setFittingParametersRange({0,100}); } } - return 1; + return true; } bool setAllFittingParameters_noRange(Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings, @@ -1426,31 +1553,43 @@ bool setAllFittingParameters_noRange(Crit3DProxyCombination myCombination, Crit3 std::vector > ¶mDelta, std::vector > ¶mFirstGuess, std::string &errorStr) { + + int elevationPos = NODATA; + std::vector> tempFirstGuess = paramFirstGuess; + unsigned int nrProxy = mySettings->getSelectedCombination().getProxySize(); + paramFirstGuess.clear(); + paramMin.resize(nrProxy); + paramMax.resize(nrProxy); + paramDelta.resize(nrProxy); + paramFirstGuess.resize(nrProxy); + + for (unsigned int i = 0; i < mySettings->getSelectedCombination().getProxySize(); i++) + { + if (getProxyPragaName(mySettings->getProxy(i)->getName()) == proxyHeight) + elevationPos = i; + } + const double RATIO_DELTA = 1000; - bool isPreviousParam = !paramFirstGuess.empty(); for (unsigned i=0; i < myCombination.getProxySize(); i++) - if (mySettings->getProxy(i)->getIsSignificant()) + if (myCombination.isProxyActive(i) && myCombination.isProxySignificant(i)) { if (getProxyPragaName(mySettings->getProxy(i)->getName()) == proxyHeight) { - if (mySettings->getChosenElevationFunction() == frei) - myFunc.push_back(lapseRateFrei); - else if (mySettings->getChosenElevationFunction() == piecewiseTwo) - myFunc.push_back(lapseRatePiecewise_two); - else if (mySettings->getChosenElevationFunction() == piecewiseThree) - myFunc.push_back(lapseRatePiecewiseForInterpolation); + if (mySettings->getChosenElevationFunction() == piecewiseTwo) + myFunc[i] = lapseRatePiecewise_two; else if (mySettings->getChosenElevationFunction() == piecewiseThreeFree) - myFunc.push_back(lapseRatePiecewiseFree); - else if (mySettings->getChosenElevationFunction() == piecewiseThreeSlope) - myFunc.push_back(lapseRatePiecewiseThree_withSlope); - else if (mySettings->getChosenElevationFunction() == freiFree) - myFunc.push_back(lapseRateFreiFree); + myFunc[i] = lapseRatePiecewise_three_free; + else if (mySettings->getChosenElevationFunction() == piecewiseThree) + myFunc[i] = lapseRatePiecewise_three; + else + { + errorStr = "Missing or wrong fitting function for proxy: " + mySettings->getProxy(i)->getName(); + return false; + } } else - { - myFunc.push_back(functionLinear); - } + myFunc[i] = functionLinear_intercept; std::vector myParam = mySettings->getProxy(i)->getFittingParametersRange(); unsigned int nrParam = unsigned(myParam.size() / 2); @@ -1474,14 +1613,16 @@ bool setAllFittingParameters_noRange(Crit3DProxyCombination myCombination, Crit3 proxyParamMin.push_back(min_); proxyParamMax.push_back(max_); proxyParamDelta.push_back((max_ - min_) / RATIO_DELTA); - proxyParamFirstGuess.push_back((max_ - min_) / 2); + proxyParamFirstGuess.push_back((max_ + min_) / 2); } - paramMin.push_back(proxyParamMin); - paramMax.push_back(proxyParamMax); - paramDelta.push_back(proxyParamDelta); - if (!isPreviousParam) - paramFirstGuess.push_back(proxyParamFirstGuess); + paramMin[i] = proxyParamMin; + paramMax[i] = proxyParamMax; + paramDelta[i] = proxyParamDelta; + if (tempFirstGuess[i].empty()) + paramFirstGuess[i] = proxyParamFirstGuess; + else + paramFirstGuess[i] = tempFirstGuess[i]; } return myFunc.size() > 0; @@ -1504,48 +1645,27 @@ bool setAllFittingParameters(Crit3DProxyCombination myCombination, Crit3DInterpo double min = mySettings->getMinMaxTemperature()[0]; double max = mySettings->getMinMaxTemperature()[1]; std::vector tempParam; - if (mySettings->getChosenElevationFunction() == frei) - { - myFunc.push_back(lapseRateFrei); - mySettings->getProxy(i)->setFittingFunctionName(frei); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {min, 0, -10, -200, 0.1, max+10, 0.006, 10, 1800, 1000}; - } - else if (mySettings->getChosenElevationFunction() == piecewiseTwo) + if (mySettings->getChosenElevationFunction() == piecewiseTwo) { myFunc.push_back(lapseRatePiecewise_two); mySettings->getProxy(i)->setFittingFunctionName(piecewiseTwo); if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) tempParam = {-200, min-2, 0, -0.006, 1800, max+2, 0.01, 0}; } - else if (mySettings->getChosenElevationFunction() == piecewiseThree) - { - myFunc.push_back(lapseRatePiecewiseForInterpolation); - mySettings->getProxy(i)->setFittingFunctionName(piecewiseThree); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {-200, min-2, 100, 0, -0.006, 1800, max+2, 1000, (max-min-2), 0}; - } else if (mySettings->getChosenElevationFunction() == piecewiseThreeFree) { - myFunc.push_back(lapseRatePiecewiseFree); + myFunc.push_back(lapseRatePiecewise_three_free); mySettings->getProxy(i)->setFittingFunctionName(piecewiseThreeFree); if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) tempParam = {-200, min-2, 100, 0.001, -0.006, -0.006, 1800, max+2, 1000, 0.01, 0, 0}; } - else if (mySettings->getChosenElevationFunction() == piecewiseThreeSlope) + else if (mySettings->getChosenElevationFunction() == piecewiseThree) { - myFunc.push_back(lapseRatePiecewiseThree_withSlope); - mySettings->getProxy(i)->setFittingFunctionName(piecewiseThreeSlope); + myFunc.push_back(lapseRatePiecewise_three); + mySettings->getProxy(i)->setFittingFunctionName(piecewiseThree); if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) tempParam = {-200, min-2, 100, 0.002, -0.006, 1800, max+2, 1000, 0.01, 0}; } - else if (mySettings->getChosenElevationFunction() == freiFree) - { - myFunc.push_back(lapseRateFreiFree); - mySettings->getProxy(i)->setFittingFunctionName(freiFree); - if (!(mySettings->getProxy(i)->getFittingParametersRange().empty())) - tempParam = {min, 0, -4, -200, 0.1, 0, max+10, 0.006, 4, 1800, 1000, 0.006}; - } mySettings->getProxy(i)->setFittingParametersRange(tempParam); } else @@ -1617,16 +1737,251 @@ std::vector getfittingParameters(Crit3DProxyCombination myCombination, return myParam; } +bool multipleDetrendingMain(std::vector &myPoints, + Crit3DInterpolationSettings* mySettings, meteoVariable myVar, std::string &errorStr) +{ + int elevationPos = NODATA; + for (unsigned int pos=0; pos < mySettings->getCurrentCombination().getProxySize(); pos++) + { + if (getProxyPragaName(mySettings->getProxy(pos)->getName()) == proxyHeight) + elevationPos = pos; + } + + std::vector> parameters = mySettings->getFittingParameters(); + mySettings->clearFitting(); + + if (mySettings->getCurrentCombination().isProxyActive(elevationPos)) + { + Crit3DProxyCombination elevationCombination; + elevationCombination.resetCombination(mySettings->getSelectedCombination().getProxySize()); + elevationCombination.setProxyActive(elevationPos, true); + + if (parameters.empty()) + parameters.resize(elevationPos + 1); + + + if (!multipleDetrendingElevation(elevationCombination, parameters[elevationPos], myPoints, mySettings, myVar, errorStr)) + return false; + } + + Crit3DProxyCombination othersCombination = mySettings->getSelectedCombination(); + othersCombination.setProxyActive(elevationPos,false); + + if (!multipleDetrending(othersCombination, parameters, myPoints, mySettings, myVar, errorStr)) + return false; + + return true; + +} -bool multipleDetrending(std::vector &myPoints, +bool multipleDetrendingElevation(Crit3DProxyCombination elevationCombination, std::vector elevationParameters, std::vector &myPoints, Crit3DInterpolationSettings* mySettings, meteoVariable myVar, std::string &errorStr) { - std::vector > parameters = mySettings->getFittingParameters(); - mySettings->clearFitting(); if (! getUseDetrendingVar(myVar)) return true; + int elevationPos = NODATA; + + for (unsigned int pos = 0; pos < elevationCombination.getProxySize(); pos++) + if (elevationCombination.isProxyActive(pos)) + elevationPos = pos; + + if (elevationPos == NODATA) + return true; + + Crit3DProxy* elevationProxy = mySettings->getProxy(elevationPos); + + //lapse rate code + std::vector elevationPoints = myPoints; + vector::iterator it = elevationPoints.begin(); + + while (it != elevationPoints.end()) + { + if (!checkLapseRateCode(it->lapseRateCode, mySettings->getUseLapseRateCode(), true)) + it = elevationPoints.erase(it); + else + it++; + } + + // proxy spatial variability (1st step) + double avg, stdDev; + unsigned validNr; + validNr = 0; + + if (proxyValidityWeighted(elevationPoints, elevationPos, elevationProxy->getStdDevThreshold(), avg, stdDev)) + { + elevationCombination.setProxySignificant(elevationPos, true); + Crit3DProxyCombination myCombination = mySettings->getSelectedCombination(); + myCombination.setProxySignificant(elevationPos, true); + mySettings->setCurrentCombination(myCombination); + elevationProxy->setIsSignificant(true); + } + else + { + elevationCombination.setProxySignificant(elevationPos, false); + Crit3DProxyCombination myCombination = mySettings->getSelectedCombination(); + myCombination.setProxyActive(elevationPos, false); + myCombination.setProxySignificant(elevationPos, false); + mySettings->setCurrentCombination(myCombination); + mySettings->getProxy(elevationPos)->setIsSignificant(false); + return true; + } + + // exclude points with incomplete proxies + unsigned i; + bool isValid; + float proxyValue; + it = myPoints.begin(); + vector::iterator elevationIt = elevationPoints.begin(); + + while (it != myPoints.end()) + { + isValid = true; + proxyValue = it->getProxyValue(elevationPos); + \ + if (proxyValue == NODATA) + isValid = false; + + if (! isValid) + it = myPoints.erase(it); + else + it++; + + isValid = true; + if (elevationIt != elevationPoints.end()) + { + proxyValue = elevationIt->getProxyValue(elevationPos); + + if (proxyValue == NODATA) + isValid = false; + if (!isValid) + elevationIt = elevationPoints.erase(elevationIt); + else + elevationIt++; + } + + } + + // proxy spatial variability (2nd step) + if (proxyValidityWeighted(elevationPoints, elevationPos, elevationProxy->getStdDevThreshold(), avg, stdDev)) + { + elevationCombination.setProxySignificant(elevationPos, true); + Crit3DProxyCombination myCombination = mySettings->getSelectedCombination(); + myCombination.setProxySignificant(elevationPos, true); + mySettings->setCurrentCombination(myCombination); + elevationProxy->setIsSignificant(true); + } + else + { + elevationCombination.setProxySignificant(elevationPos, false); + Crit3DProxyCombination myCombination = mySettings->getSelectedCombination(); + myCombination.setProxyActive(elevationPos, false); + myCombination.setProxySignificant(elevationPos, false); + mySettings->setCurrentCombination(myCombination); + elevationProxy->setIsSignificant(false); + return true; + } + + // filling vectors + std::vector predictors; + std::vector predictands; + std::vector weights; + + for (i=0; i < myPoints.size(); i++) + { + if (checkLapseRateCode(myPoints[i].lapseRateCode, mySettings->getUseLapseRateCode(), true)) + { + predictors.push_back(myPoints[i].getProxyValue(elevationPos)); + predictands.push_back(myPoints[i].value); + weights.push_back(myPoints[i].regressionWeight*myPoints[i].heightWeight); + } + } + + if (mySettings->getUseLocalDetrending() && elevationPoints.size() < mySettings->getMinPointsLocalDetrending()) + { + elevationProxy->setIsSignificant(false); + Crit3DProxyCombination myCombination = mySettings->getSelectedCombination(); + myCombination.setProxyActive(elevationPos, false); + myCombination.setProxySignificant(elevationPos, false); + mySettings->setCurrentCombination(myCombination); + return true; + } + + std::vector > parametersMin; + std::vector > parametersMax; + std::vector > parametersDelta; + std::vector > parameters; + parameters.resize(mySettings->getCurrentCombination().getProxySize()); + std::vector&)>> myFunc(mySettings->getCurrentCombination().getProxySize(), nullptr); + + unsigned int nrMaxStep = 200; + if (elevationParameters.empty()) + nrMaxStep *= 10; + else + parameters[elevationPos] = elevationParameters; + + if (! setAllFittingParameters_noRange(elevationCombination, mySettings, myFunc, parametersMin, parametersMax, + parametersDelta, parameters, errorStr)) + { + errorStr = "couldn't prepare the fitting parameters for proxy: elevation."; + return false; + } + + auto func = myFunc[elevationPos].target&)>(); + + if (!func) + { + errorStr = "wrong or missing fitting function for proxy: elevation."; + return false; + } + + // multiple non linear fitting + interpolation::bestFittingMarquardt_nDimension_singleFunction(*func, nrMaxStep, 4, parametersMin[elevationPos], parametersMax[elevationPos], parameters[elevationPos], parametersDelta[elevationPos], + 100, 0.005, 0.002, predictors, predictands, weights); + + + mySettings->setSingleFittingParameters(parameters[elevationPos], elevationPos); + + + if (mySettings->getProxy(elevationPos)->getFittingFunctionName() == piecewiseTwo) + { + myFunc[elevationPos] = detrendingLapseRatePiecewise_two; + mySettings->setSingleFittingFunction(detrendingLapseRatePiecewise_two, elevationPos); + } else if (mySettings->getProxy(elevationPos)->getFittingFunctionName() == piecewiseThreeFree) + { + myFunc[elevationPos] = detrendingLapseRatePiecewise_three_free; + mySettings->setSingleFittingFunction(detrendingLapseRatePiecewise_three_free, elevationPos); + } else if (mySettings->getProxy(elevationPos)->getFittingFunctionName() == piecewiseThree) + { + myFunc[elevationPos] = detrendingLapseRatePiecewise_three; + mySettings->setSingleFittingFunction(detrendingLapseRatePiecewise_three, elevationPos); + } - Crit3DProxyCombination myCombination = mySettings->getSelectedCombination(); + func = myFunc[elevationPos].target&)>();; + + // detrending + float detrendValue; + for (i = 0; i < myPoints.size(); i++) + { + proxyValue = myPoints[i].getProxyValue(elevationPos); + + detrendValue = float((*func)(proxyValue, parameters[elevationPos])); + myPoints[i].value -= detrendValue; + } + + return true; +} + +bool multipleDetrending(Crit3DProxyCombination othersCombination, std::vector> parameters, std::vector &myPoints, + Crit3DInterpolationSettings* mySettings, meteoVariable myVar, std::string &errorStr) +{ + if (! getUseDetrendingVar(myVar)) return true; + + int elevationPos = NODATA; + for (unsigned int tempPos=0; tempPos < mySettings->getCurrentCombination().getProxySize(); tempPos++) + { + if (getProxyPragaName(mySettings->getProxy(tempPos)->getName()) == proxyHeight) + elevationPos = tempPos; + } // verify predictors number unsigned nrPredictors = 0; @@ -1635,7 +1990,7 @@ bool multipleDetrending(std::vector &myPoints, int proxyNr = int(mySettings->getProxyNr()); for (int pos=0; pos < proxyNr; pos++) { - if (myCombination.isProxyActive(pos)) + if (othersCombination.isProxyActive(pos)) { myProxy = mySettings->getProxy(pos); myProxy->setIsSignificant(false); @@ -1646,6 +2001,17 @@ bool multipleDetrending(std::vector &myPoints, if (nrPredictors == 0) return true; + //lapse rate code + std::vector othersPoints = myPoints; + vector::iterator it = othersPoints.begin(); + while (it != othersPoints.end()) + { + if (!checkLapseRateCode(it->lapseRateCode, mySettings->getUseLapseRateCode(), false)) + it = othersPoints.erase(it); + else + it++; + } + // proxy spatial variability (1st step) double avg, stdDev; unsigned validNr; @@ -1653,10 +2019,27 @@ bool multipleDetrending(std::vector &myPoints, for (int pos=0; pos < proxyNr; pos++) { - if (myCombination.isProxyActive(pos) && proxyValidity(myPoints, pos, mySettings->getProxy(pos)->getStdDevThreshold(), avg, stdDev)) + if (othersCombination.isProxyActive(pos)) { - mySettings->getProxy(pos)->setIsSignificant(true); - validNr++; + if (proxyValidityWeighted(othersPoints, pos, mySettings->getProxy(pos)->getStdDevThreshold(), avg, stdDev)) + { + othersCombination.setProxySignificant(pos, true); + Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); + myCombination.setProxySignificant(pos, true); + mySettings->setCurrentCombination(myCombination); + mySettings->getProxy(pos)->setIsSignificant(true); + validNr++; + } + else + { + othersCombination.setProxySignificant(pos, false); + Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); + myCombination.setProxyActive(pos, false); + myCombination.setProxySignificant(pos, false); + mySettings->setCurrentCombination(myCombination); + mySettings->getProxy(pos)->setIsSignificant(false); + + } } } @@ -1666,7 +2049,7 @@ bool multipleDetrending(std::vector &myPoints, unsigned i; bool isValid; float proxyValue; - vector::iterator it = myPoints.begin(); + it = myPoints.begin(); while (it != myPoints.end()) { @@ -1691,20 +2074,55 @@ bool multipleDetrending(std::vector &myPoints, } } + it = othersPoints.begin(); + while (it != othersPoints.end()) + { + isValid = true; + for (int pos=0; pos < proxyNr; pos++) + if (mySettings->getProxy(pos)->getIsSignificant()) + { + proxyValue = it->getProxyValue(pos); + if (proxyValue == NODATA) + { + isValid = false; + break; + } + } + + if (! isValid) + { + it = othersPoints.erase(it); + } + else { + it++; + } + } + // proxy spatial variability (2nd step) validNr = 0; for (int pos=0; pos < proxyNr; pos++) { - if (myCombination.isProxyActive(pos) && proxyValidity(myPoints, pos, mySettings->getProxy(pos)->getStdDevThreshold(), avg, stdDev)) + if (othersCombination.isProxyActive(pos)) { - mySettings->getProxy(pos)->setIsSignificant(true); - validNr++; - } - else - { - mySettings->getProxy(pos)->setIsSignificant(false); - if (getProxyPragaName(mySettings->getProxy(pos)->getName()) == proxyHeight) - return true; + if (proxyValidityWeighted(othersPoints, pos, mySettings->getProxy(pos)->getStdDevThreshold(), avg, stdDev)) + { + othersCombination.setProxySignificant(pos, true); + Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); + myCombination.setProxySignificant(pos, true); + mySettings->setCurrentCombination(myCombination); + mySettings->getProxy(pos)->setIsSignificant(true); + validNr++; + } + else + { + othersCombination.setProxySignificant(pos, false); + Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); + myCombination.setProxyActive(pos, false); + myCombination.setProxySignificant(pos, false); + mySettings->setCurrentCombination(myCombination); + mySettings->getProxy(pos)->setIsSignificant(false); + + } } } @@ -1720,7 +2138,7 @@ bool multipleDetrending(std::vector &myPoints, { rowPredictors.clear(); for (int pos=0; pos < proxyNr; pos++) - if ((mySettings->getProxy(pos)->getIsSignificant())) + if (othersCombination.isProxyActive(pos) && othersCombination.isProxySignificant(pos) && checkLapseRateCode(myPoints[i].lapseRateCode, mySettings->getUseLapseRateCode(), false)) { proxyValue = myPoints[i].getProxyValue(pos); rowPredictors.push_back(proxyValue); @@ -1731,11 +2149,19 @@ bool multipleDetrending(std::vector &myPoints, weights.push_back(myPoints[i].regressionWeight); } - if (mySettings->getUseLocalDetrending() && myPoints.size() < mySettings->getMinPointsLocalDetrending()) + if (mySettings->getUseLocalDetrending() && othersPoints.size() < mySettings->getMinPointsLocalDetrending()) { + Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); for (int pos = 0; pos < proxyNr; pos++) - mySettings->getProxy(pos)->setIsSignificant(false); - + { + if (pos != elevationPos) + { + myCombination.setProxyActive(pos, false); + myCombination.setProxySignificant(pos, false); + mySettings->getProxy(pos)->setIsSignificant(false); + } + } + mySettings->setCurrentCombination(myCombination); return true; } @@ -1743,24 +2169,49 @@ bool multipleDetrending(std::vector &myPoints, std::vector > parametersMax; std::vector > parametersDelta; //std::vector > parameters; - std::vector&)>> myFunc; + std::vector&)>> myFunc(mySettings->getCurrentCombination().getProxySize(), nullptr); - unsigned int nrMaxStep = 100; + unsigned int nrMaxStep = 10; if (parameters.empty()) nrMaxStep *= 10; - if (! setAllFittingParameters_noRange(myCombination, mySettings, myFunc, parametersMin, parametersMax, + if (! setAllFittingParameters_noRange(othersCombination, mySettings, myFunc, parametersMin, parametersMax, parametersDelta, parameters, errorStr)) - { return false; + + std::vector&)>> fullFunc = myFunc; + myFunc.clear(); + + for (const auto& function : fullFunc) { + if (function) { + myFunc.push_back(function); + } } + removeEmptyFittingParameters(parameters); + removeEmptyFittingParameters(parametersMin); + removeEmptyFittingParameters(parametersMax); + removeEmptyFittingParameters(parametersDelta); + // multiple non linear fitting interpolation::bestFittingMarquardt_nDimension(&functionSum, myFunc, nrMaxStep, 4, parametersMin, parametersMax, parameters, parametersDelta, - 100, 0.005, 0.002, predictors, predictands, weights); + 100, 0.005, 0.002, predictors, predictands, weights, elevationPos); - mySettings->setFittingFunction(myFunc); - mySettings->setFittingParameters(parameters); + myFunc.clear(); + int k = 0; + for (unsigned int i = 0; i < othersCombination.getProxySize(); i++) + { + if (i != elevationPos && othersCombination.isProxyActive(i) && othersCombination.isProxySignificant(i)) + { + if (k < parameters.size()) + { + mySettings->setSingleFittingParameters(parameters[k], i); + mySettings->setSingleFittingFunction(functionLinear, i); + } + k++; + myFunc.push_back(functionLinear); + } + } std::vector proxyValues; @@ -1769,10 +2220,10 @@ bool multipleDetrending(std::vector &myPoints, for (i = 0; i < myPoints.size(); i++) { proxyValues.clear(); - + for (int pos=0; pos < proxyNr; pos++) { - if ((mySettings->getProxy(pos)->getIsSignificant())) + if ((othersCombination.isProxyActive(pos)) && othersCombination.isProxySignificant(pos)) { proxyValue = myPoints[i].getProxyValue(pos); proxyValues.push_back(double(proxyValue)); @@ -1781,6 +2232,7 @@ bool multipleDetrending(std::vector &myPoints, detrendValue = float(functionSum(myFunc, proxyValues, parameters)); myPoints[i].value -= detrendValue; + } return true; @@ -1792,8 +2244,7 @@ void topographicDistanceOptimize(meteoVariable myVar, int nrMeteoPoints, std::vector &interpolationPoints, Crit3DInterpolationSettings* mySettings, - Crit3DMeteoSettings* meteoSettings, - const Crit3DTime &myTime) + Crit3DMeteoSettings* meteoSettings) { float avgError; @@ -1807,7 +2258,7 @@ void topographicDistanceOptimize(meteoVariable myVar, mySettings->setTopoDist_Kh(kh); if (computeResiduals(myVar, myMeteoPoints, nrMeteoPoints, interpolationPoints, mySettings, meteoSettings, true, true)) { - avgError = computeErrorCrossValidation(myVar, myMeteoPoints, nrMeteoPoints, myTime, meteoSettings); + avgError = computeErrorCrossValidation(myMeteoPoints, nrMeteoPoints); if (isEqual(bestError, NODATA) || avgError < bestError) { bestError = avgError; @@ -1850,11 +2301,11 @@ void optimalDetrending(meteoVariable myVar, Crit3DMeteoPoint* &myMeteoPoints, in mySettings->setCurrentCombination(myCombination); if (mySettings->getUseTD() && getUseTdVar(myVar)) - topographicDistanceOptimize(myVar, myMeteoPoints, nrMeteoPoints, interpolationPoints, mySettings, meteoSettings, myTime); + topographicDistanceOptimize(myVar, myMeteoPoints, nrMeteoPoints, interpolationPoints, mySettings, meteoSettings); if (computeResiduals(myVar, myMeteoPoints, nrMeteoPoints, interpolationPoints, mySettings, meteoSettings, true, true)) { - avgError = computeErrorCrossValidation(myVar, myMeteoPoints, nrMeteoPoints, myTime, meteoSettings); + avgError = computeErrorCrossValidation(myMeteoPoints, nrMeteoPoints); if (! isEqual(avgError, NODATA) && (isEqual(minError, NODATA) || avgError < minError)) { minError = avgError; @@ -1879,6 +2330,7 @@ bool preInterpolation(std::vector &myPoints, Crit Crit3DClimateParameters* myClimate, Crit3DMeteoPoint* myMeteoPoints, int nrMeteoPoints, meteoVariable myVar, Crit3DTime myTime, std::string &errorStr) { + if (myVar == precipitation || myVar == dailyPrecipitation) { int nrPrecNotNull; @@ -1895,10 +2347,10 @@ bool preInterpolation(std::vector &myPoints, Crit { if (mySettings->getUseMultipleDetrending()) { + mySettings->setCurrentCombination(mySettings->getSelectedCombination()); if (mySettings->getProxiesComplete()) { - mySettings->setCurrentCombination(mySettings->getSelectedCombination()); - if (! multipleDetrending(myPoints, mySettings, myVar, errorStr)) return false; + if (! multipleDetrendingMain(myPoints, mySettings, myVar, errorStr)) return false; } } else @@ -1917,7 +2369,9 @@ bool preInterpolation(std::vector &myPoints, Crit } if (mySettings->getUseTD() && getUseTdVar(myVar)) - topographicDistanceOptimize(myVar, myMeteoPoints, nrMeteoPoints, myPoints, mySettings, meteoSettings, myTime); + { + topographicDistanceOptimize(myVar, myMeteoPoints, nrMeteoPoints, myPoints, mySettings, meteoSettings); + } return true; } @@ -1971,19 +2425,18 @@ float interpolate(vector &myPoints, Crit3DInterpo } -bool getActiveProxyValues(Crit3DInterpolationSettings *mySettings, const std::vector &allProxyValues, std::vector &activeProxyValues) +bool getActiveProxyValues(Crit3DProxyCombination myCombination, const std::vector &allProxyValues, std::vector &activeProxyValues) { - Crit3DProxyCombination myCombination = mySettings->getCurrentCombination(); - if (allProxyValues.size() != mySettings->getProxyNr()) + if (allProxyValues.size() != myCombination.getProxySize()) return false; activeProxyValues.clear(); bool isComplete = true; - for (unsigned int i=0; i < mySettings->getProxyNr(); i++) - if (myCombination.isProxyActive(i) && mySettings->getProxy(i)->getIsSignificant()) + for (unsigned int i=0; i < myCombination.getProxySize(); i++) + if (myCombination.isProxyActive(i) && myCombination.isProxySignificant(i)) { activeProxyValues.push_back(allProxyValues[i]); if (allProxyValues[i] == NODATA) @@ -1993,6 +2446,16 @@ bool getActiveProxyValues(Crit3DInterpolationSettings *mySettings, const std::ve return (activeProxyValues.size() > 0 && isComplete); } +void removeEmptyFittingParameters(std::vector > &fittingParameters) +{ + auto newEnd = std::remove_if(fittingParameters.begin(), fittingParameters.end(), [](const std::vector& v) { + return v.empty(); + }); + + fittingParameters.erase(newEnd, fittingParameters.end()); + + return; +} bool getProxyValuesXY(float x, float y, Crit3DInterpolationSettings* mySettings, std::vector &myValues) { diff --git a/agrolib/interpolation/interpolation.h b/agrolib/interpolation/interpolation.h index b91da243..88cbff1e 100644 --- a/agrolib/interpolation/interpolation.h +++ b/agrolib/interpolation/interpolation.h @@ -61,15 +61,23 @@ float interpolate(std::vector &myPoints, Crit3DInterpolationSettings *mySettings, Crit3DMeteoSettings *meteoSettings, meteoVariable myVar, float myX, float myY, float myZ, std::vector myProxyValues, bool excludeSupplemental); bool getProxyValuesXY(float x, float y, Crit3DInterpolationSettings* mySettings, std::vector &myValues); - bool getActiveProxyValues(Crit3DInterpolationSettings *mySettings, const std::vector &allProxyValues, std::vector &activeProxyValues); + bool getActiveProxyValues(Crit3DProxyCombination myCombination, const std::vector &allProxyValues, std::vector &activeProxyValues); + + void removeEmptyFittingParameters(std::vector > &fittingParameters); void detrending(std::vector &myPoints, Crit3DProxyCombination myCombination, Crit3DInterpolationSettings *mySettings, Crit3DClimateParameters *myClimate, meteoVariable myVar, Crit3DTime myTime); - bool multipleDetrending(std::vector &myPoints, Crit3DInterpolationSettings* mySettings, + bool multipleDetrendingMain(std::vector &myPoints, + Crit3DInterpolationSettings* mySettings, meteoVariable myVar, std::string &errorStr); + + bool multipleDetrending(Crit3DProxyCombination othersCombination, std::vector > parameters, std::vector &myPoints, Crit3DInterpolationSettings* mySettings, meteoVariable myVar, std::string &errorStr); + bool multipleDetrendingElevation(Crit3DProxyCombination myCombination, std::vector elevationParameters, std::vector &myPoints, + Crit3DInterpolationSettings* mySettings, meteoVariable myVar, std::string &errorStr); + bool getUseDetrendingVar(meteoVariable myVar); bool isThermal(meteoVariable myVar); bool getUseTdVar(meteoVariable myVar); @@ -90,12 +98,18 @@ void localSelection(std::vector &inputPoints, std::vector &selectedPoints, - float x, float y, Crit3DInterpolationSettings &mySettings); + float x, float y, float z, Crit3DInterpolationSettings &mySettings); + + void localSelection_new(std::vector &inputPoints, std::vector &selectedPoints, + float x, float y, float z, Crit3DInterpolationSettings& mySettings); bool proxyValidity(std::vector &myPoints, int proxyPos, float stdDevThreshold, double &avg, double &stdDev); - bool setAllFittingRanges(Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings); + bool proxyValidityWeighted(std::vector &myPoints, int proxyPos, + float stdDevThreshold, double &avg, double &stdDev); + + bool setHeightFittingRange(Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings); bool setAllFittingParameters_noRange(Crit3DProxyCombination myCombination, Crit3DInterpolationSettings* mySettings, std::vector&)>>& myFunc, diff --git a/agrolib/interpolation/interpolationConstants.h b/agrolib/interpolation/interpolationConstants.h index b16c8ac2..c6b3013a 100644 --- a/agrolib/interpolation/interpolationConstants.h +++ b/agrolib/interpolation/interpolationConstants.h @@ -31,21 +31,19 @@ { "orography", proxyHeight }, { "orogIndex", proxyOrogIndex }, { "urbanFraction", proxyUrbanFraction }, + { "urban", proxyUrbanFraction}, { "seaDistance", proxySeaDistance }, { "aspect", proxyAspect }, { "slope", proxySlope }, { "water_index", proxyWaterIndex} }; - enum TFittingFunction { piecewiseTwo, piecewiseThree, piecewiseThreeFree, piecewiseThreeSlope, frei, freiFree, linear, noFunction }; + enum TFittingFunction { piecewiseTwo, piecewiseThreeFree, piecewiseThree, linear, noFunction }; const std::map fittingFunctionNames = { - { "Double piecewise", piecewiseTwo }, - { "Triple piecewise", piecewiseThree }, - { "Triple piecewise (6 parameters)", piecewiseThreeFree}, - { "Triple piecewise (5 parameters)", piecewiseThreeSlope}, - { "Nonlinear Frei function (5 parameters)", frei }, - { "Nonlinear Frei function (6 parameters)", freiFree}, + { "piecewise_two", piecewiseTwo }, + { "free_triple_piecewise", piecewiseThreeFree}, + { "triple_piecewise", piecewiseThree}, { "linear", linear } }; diff --git a/agrolib/interpolation/interpolationPoint.h b/agrolib/interpolation/interpolationPoint.h index 82caaef5..126df5b9 100644 --- a/agrolib/interpolation/interpolationPoint.h +++ b/agrolib/interpolation/interpolationPoint.h @@ -22,6 +22,7 @@ float distance; float value; float regressionWeight; + float heightWeight; lapseRateCodeType lapseRateCode; gis::Crit3DRasterGrid* topographicDistance; std::vector proxyValues; diff --git a/agrolib/interpolation/interpolationSettings.cpp b/agrolib/interpolation/interpolationSettings.cpp index 1024f5f5..683472d1 100644 --- a/agrolib/interpolation/interpolationSettings.cpp +++ b/agrolib/interpolation/interpolationSettings.cpp @@ -139,9 +139,10 @@ void Crit3DInterpolationSettings::setSelectedCombination(const Crit3DProxyCombin selectedCombination = value; } -void Crit3DInterpolationSettings::setValueSelectedCombination(unsigned int index, bool isActive) +void Crit3DInterpolationSettings::setActiveSelectedCombination(unsigned int index, bool isActive) { selectedCombination.setProxyActive(index, isActive); + selectedCombination.setProxySignificant(index, false); } unsigned Crit3DInterpolationSettings::getIndexHeight() const @@ -164,6 +165,7 @@ Crit3DProxyCombination Crit3DInterpolationSettings::getCurrentCombination() cons return currentCombination; } + std::vector Crit3DInterpolationSettings::getCurrentProxy() const { return currentProxy; @@ -281,11 +283,35 @@ std::vector > Crit3DInterpolationSettings::getFittingParamet return fittingParameters; } +std::vector Crit3DInterpolationSettings::getProxyFittingParameters(int tempIndex) +{ + if (tempIndex < fittingParameters.size()) + return fittingParameters[tempIndex]; + else { + fittingParameters.resize(tempIndex + 1); + return fittingParameters[tempIndex]; + } +} + void Crit3DInterpolationSettings::setFittingParameters(const std::vector > &newFittingParameters) { fittingParameters = newFittingParameters; } +void Crit3DInterpolationSettings::setSingleFittingParameters(std::vector &newFittingParameters, int paramIndex) +{ + if (fittingParameters.size() <= paramIndex) + fittingParameters.resize(paramIndex+1); + fittingParameters[paramIndex] = newFittingParameters; +} + +void Crit3DInterpolationSettings::addFittingParameters(const std::vector > &newFittingParameters) +{ + for (size_t i = 0; i < newFittingParameters.size(); ++i) { + fittingParameters.push_back(newFittingParameters[i]); + } +} + std::vector &)>> Crit3DInterpolationSettings::getFittingFunction() const { return fittingFunction; @@ -296,14 +322,57 @@ void Crit3DInterpolationSettings::setFittingFunction(const std::vector &)> &newFittingFunction, unsigned int index) +{ + if (fittingFunction.size() <= index) + fittingFunction.resize(index + 1); + fittingFunction[index] = newFittingFunction; + +} + TFittingFunction Crit3DInterpolationSettings::getChosenElevationFunction() { - return chosenElevationFunction; + int elPos = NODATA; + for (int i = 0; i < getProxyNr(); i++) + if (getProxyPragaName(getProxy(i)->getName()) == proxyHeight) + elPos = i; + + if (elPos != NODATA) + return getProxy(elPos)->getFittingFunctionName(); + else + return noFunction; } void Crit3DInterpolationSettings::setChosenElevationFunction(TFittingFunction chosenFunction) { - chosenElevationFunction = chosenFunction; + int elPos = NODATA; + for (int i = 0; i < getProxyNr(); i++) + if (getProxyPragaName(getProxy(i)->getName()) == proxyHeight) + elPos = i; + + double min = -20; + double max = 40; + + if (!getMinMaxTemperature().empty()) + { + min = getMinMaxTemperature()[0]; + max = getMinMaxTemperature()[1]; + } + + if (elPos != NODATA) + { + if (chosenFunction == piecewiseTwo) + getProxy(elPos)->setFittingParametersRange({-200, min-4, 0.002, -0.01, 5000, max+4, 0.01, 0.0015}); + else if (chosenFunction == piecewiseThree) + getProxy(elPos)->setFittingParametersRange({-200, min-4, 300, 0.002, -0.01, 5000, max+4, 1000, 0.007, 0.0015}); + else if (chosenFunction == piecewiseThreeFree) + getProxy(elPos)->setFittingParametersRange({-200, min-4, 300, 0.002, -0.01, -0.01, 5000, max+4, 1000, 0.007, 0.0015, 0.0015}); + else return; + + getProxy(elPos)->setFittingFunctionName(chosenFunction); + } + else + return; } void Crit3DInterpolationSettings::setMinMaxTemperature(double min, double max) @@ -367,7 +436,9 @@ void Crit3DInterpolationSettings::initialize() meteoGridAggrMethod = aggrAverage; meteoGridUpscaleFromDem = true; indexHeight = unsigned(NODATA); - chosenElevationFunction = piecewiseThreeSlope; + + fittingFunction.clear(); + fittingParameters.clear(); isKrigingReady = false; precipitationAllZero = false; @@ -737,7 +808,9 @@ void Crit3DInterpolationSettings::addProxy(Crit3DProxy myProxy, bool isActive_) setIndexHeight(int(currentProxy.size())-1); selectedCombination.addProxyActive(isActive_); + selectedCombination.addProxySignificant(false); optimalCombination.addProxyActive(isActive_); + optimalCombination.addProxySignificant(false); } std::string Crit3DInterpolationSettings::getProxyName(unsigned pos) @@ -761,9 +834,47 @@ Crit3DProxyCombination::Crit3DProxyCombination() void Crit3DProxyCombination::clear() { _isActiveList.clear(); + _isSignificantList.clear(); _useThermalInversion = false; } +void Crit3DProxyCombination::resetCombination(unsigned int size) +{ + _isActiveList.resize(size); + _isSignificantList.resize(size); + for (unsigned int i = 0; i < size; i++) + { + setProxyActive(i, false); + setProxySignificant(i, false); + } + _useThermalInversion = false; +} + +unsigned int Crit3DProxyCombination::getActiveProxySize() +{ + unsigned int size = 0; + for (unsigned int i = 0; i < getProxySize(); i++) + if (isProxyActive(i)) size++; + + return size; +} + +void Crit3DProxyCombination::setAllActiveToFalse() +{ + for (unsigned int i = 0; i < _isActiveList.size(); i++) + setProxyActive(i, false); + + return; +} + +void Crit3DProxyCombination::setAllSignificantToFalse() +{ + for (unsigned int i = 0; i < _isActiveList.size(); i++) + setProxySignificant(i, false); + + return; +} + bool Crit3DInterpolationSettings::getCombination(int combinationInteger, Crit3DProxyCombination &outCombination) { diff --git a/agrolib/interpolation/interpolationSettings.h b/agrolib/interpolation/interpolationSettings.h index c359154c..87744cdb 100644 --- a/agrolib/interpolation/interpolationSettings.h +++ b/agrolib/interpolation/interpolationSettings.h @@ -107,6 +107,7 @@ { private: std::vector _isActiveList; + std::vector _isSignificantList; bool _useThermalInversion; public: @@ -116,7 +117,17 @@ void addProxyActive(bool value) { _isActiveList.push_back(value); } void setProxyActive(unsigned index, bool value) { _isActiveList[index] = value; } bool isProxyActive(unsigned index) { return _isActiveList[index]; } + std::vector getActiveList() { return _isActiveList; } + void addProxySignificant(bool value) { _isSignificantList.push_back(value); } + void setProxySignificant(unsigned index, bool value) { _isSignificantList[index] = value; } + bool isProxySignificant(unsigned index) { return _isSignificantList[index]; } + + void resetCombination(unsigned int size); + void setAllActiveToFalse(); + void setAllSignificantToFalse(); + + unsigned int getActiveProxySize(); unsigned int getProxySize() const { return unsigned(_isActiveList.size()); } bool getUseThermalInversion() const { return _useThermalInversion; } @@ -130,7 +141,6 @@ gis::Crit3DRasterGrid* currentDEM; //for TD TInterpolationMethod interpolationMethod; - TFittingFunction chosenElevationFunction; float minRegressionR2; bool useThermalInversion; @@ -224,7 +234,7 @@ void setOptimalCombination(const Crit3DProxyCombination &value); Crit3DProxyCombination getSelectedCombination() const; void setSelectedCombination(const Crit3DProxyCombination &value); - void setValueSelectedCombination(unsigned int index, bool isActive); + void setActiveSelectedCombination(unsigned int index, bool isActive); unsigned getIndexHeight() const; void setIndexHeight(unsigned value); Crit3DProxyCombination getCurrentCombination() const; @@ -253,9 +263,13 @@ void setMinPointsLocalDetrending(int newMinPointsLocalDetrending); std::vector> getFittingParameters() const; + std::vector getProxyFittingParameters(int tempIndex); void setFittingParameters(const std::vector> &newFittingParameters); + void setSingleFittingParameters(std::vector &newFittingParameters, int paramIndex); + void addFittingParameters(const std::vector > &newFittingParameters); std::vector &)> > getFittingFunction() const; void setFittingFunction(const std::vector &)> > &newFittingFunction); + void setSingleFittingFunction(const std::function &)> &newFittingFunction, unsigned int index); bool getProxiesComplete() const; void setProxiesComplete(bool newProxiesComplete); void clearFitting(); diff --git a/agrolib/interpolation/spatialControl.cpp b/agrolib/interpolation/spatialControl.cpp index f7834caf..932e0130 100644 --- a/agrolib/interpolation/spatialControl.cpp +++ b/agrolib/interpolation/spatialControl.cpp @@ -84,9 +84,6 @@ bool computeResiduals(meteoVariable myVar, Crit3DMeteoPoint* meteoPoints, int nr if (myVar == noMeteoVar) return false; - float myValue, interpolatedValue; - interpolatedValue = NODATA; - myValue = NODATA; std::vector myProxyValues; bool isValid; @@ -101,58 +98,67 @@ bool computeResiduals(meteoVariable myVar, Crit3DMeteoPoint* meteoPoints, int nr if (isValid && meteoPoints[i].quality == quality::accepted) { - myValue = meteoPoints[i].currentValue; + float myValue = meteoPoints[i].currentValue; - interpolatedValue = interpolate(interpolationPoints, settings, meteoSettings, myVar, + float interpolatedValue = interpolate(interpolationPoints, settings, meteoSettings, myVar, float(meteoPoints[i].point.utm.x), float(meteoPoints[i].point.utm.y), float(meteoPoints[i].point.z), myProxyValues, false); - if ( myVar == precipitation - || myVar == dailyPrecipitation) + if ( myVar == precipitation || myVar == dailyPrecipitation) { if (myValue != NODATA) - if (myValue < meteoSettings->getRainfallThreshold()) myValue=0.; + { + if (myValue < meteoSettings->getRainfallThreshold()) + myValue=0.; + } if (interpolatedValue != NODATA) - if (interpolatedValue < meteoSettings->getRainfallThreshold()) interpolatedValue=0.; + { + if (interpolatedValue < meteoSettings->getRainfallThreshold()) + interpolatedValue=0.; + } } // TODO derived var if ((interpolatedValue != NODATA) && (myValue != NODATA)) + { meteoPoints[i].residual = interpolatedValue - myValue; + } } } return true; } -float computeErrorCrossValidation(meteoVariable myVar, Crit3DMeteoPoint* myPoints, int nrMeteoPoints, const Crit3DTime& myTime, Crit3DMeteoSettings* meteoSettings) + +float computeErrorCrossValidation(Crit3DMeteoPoint* myPoints, int nrMeteoPoints) { std::vector obsValues, estValues; - float myValue, myEstimate, myResidual; for (int i=0; i < nrMeteoPoints; i++) { if (myPoints[i].active) { - myValue = myPoints[i].getMeteoPointValue(myTime, myVar, meteoSettings); - myResidual = myPoints[i].residual; + float value = myPoints[i].currentValue; + float residual = myPoints[i].residual; - if (myValue != NODATA && myResidual != NODATA) + if (value != NODATA && residual != NODATA) { - myEstimate = myValue + myResidual; - obsValues.push_back(myValue); - estValues.push_back(myEstimate); + obsValues.push_back(value); + estValues.push_back(value + residual); } } } if (obsValues.size() > 0) + { return statistics::meanAbsoluteError(obsValues, estValues); - else return NODATA; + } + else + return NODATA; } diff --git a/agrolib/interpolation/spatialControl.h b/agrolib/interpolation/spatialControl.h index 1cb2d7e9..347efdb8 100644 --- a/agrolib/interpolation/spatialControl.h +++ b/agrolib/interpolation/spatialControl.h @@ -31,7 +31,7 @@ bool computeResiduals(meteoVariable myVar, Crit3DMeteoPoint* meteoPoints, int nrMeteoPoints, std::vector &interpolationPoints, Crit3DInterpolationSettings* settings, Crit3DMeteoSettings* meteoSettings, bool excludeOutsideDem, bool excludeSupplemental); - float computeErrorCrossValidation(meteoVariable myVar, Crit3DMeteoPoint *myPoints, int nrMeteoPoints, const Crit3DTime& myTime, Crit3DMeteoSettings *meteoSettings); + float computeErrorCrossValidation(Crit3DMeteoPoint *myPoints, int nrMeteoPoints); bool spatialQualityControl(meteoVariable myVar, Crit3DMeteoPoint* meteoPoints, int nrMeteoPoints, Crit3DInterpolationSettings *settings, Crit3DMeteoSettings* meteoSettings, diff --git a/agrolib/mathFunctions/commonConstants.h b/agrolib/mathFunctions/commonConstants.h index 13090068..1342b496 100644 --- a/agrolib/mathFunctions/commonConstants.h +++ b/agrolib/mathFunctions/commonConstants.h @@ -92,6 +92,9 @@ #define MEAN_GEOMETRIC 0 #define MEAN_LOGARITHMIC 1 + // maximum soil depth for evaporation computation [m] + #define MAX_EVAPORATION_DEPTH 0.25 + //#define BOUNDARY_SURFACE 1 #define BOUNDARY_RUNOFF 2 #define BOUNDARY_FREEDRAINAGE 3 diff --git a/agrolib/mathFunctions/furtherMathFunctions.cpp b/agrolib/mathFunctions/furtherMathFunctions.cpp index 839d3456..a85d650f 100644 --- a/agrolib/mathFunctions/furtherMathFunctions.cpp +++ b/agrolib/mathFunctions/furtherMathFunctions.cpp @@ -69,33 +69,8 @@ double lapseRateFrei(double x, std::vector & par) return y - 0.5*par[2]*(1 + cos(PI*(x-par[3])/(par[4]))); } -double lapseRateFreiFree(double x, std::vector & par) -{ - /* - par[0] = T0; - par[1] = gamma1; - par[2] = a; - par[3] = h0; - par[4] = h1-h0; - par[5] = gamma2 - */ - if (par.size() < 6) return NODATA; - - double h1 = par[3]+par[4]; - if (x <= par[3]) - { - return par[0] - par[1]*x - par[2]; - } - else if (x >= (par[4]+par[3])) - { - return par[0] - par[5]*x; - } - return par[0] - ((par[5]*par[3]+par[1]*h1)/(par[3]+h1))*x - 0.5*par[2]*(1 + cos(PI*(x-par[3])/(par[4]))); -} - - -double lapseRatePiecewise_three(double x, std::vector & par) +double lapseRatePiecewise_three_noSlope(double x, std::vector & par) { // the piecewise line is parameterized as follows // the line passes through A(par[0];par[1])and B(par[0]+par[2];par[3]). par[4] is the slope of the 2 externals pieces @@ -123,36 +98,23 @@ double lapseRatePiecewise_three(double x, std::vector & par) } } -double lapseRatePiecewiseForInterpolation(double x, std::vector & par) + +double lapseRatePiecewise_three(double x, std::vector & par) { - // the piecewise line is parameterized as follows - // the line passes through A(par[0];par[1])and B(par[0]+par[2];par[1]+par[3]). par[4] is the slope of the 2 externals pieces - // "y = mx + q" piecewise function; - double xb; + //xa (par[0],par[1]), xb-xa = par[2], par[3] is the slope of the middle piece, + //par[4] the slope of the first and last piece par[2] = MAXVALUE(10, par[2]); - // par[2] means the delta between the two quotes. It must be positive. - xb = par[0]+par[2]; + double xb = par[2]+par[0]; + if (x < par[0]) - { - //m = par[4];; - //q = par[1]-m*par[0]; - return par[4]*x + par[1]-par[4]*par[0]; - } - else if (x>xb) - { - //m = par[4]; - //q = (par[1]+par[3])-m*xb; - return par[4]*x + (par[1]+par[3])-par[4]*xb; - } + return par[4]*x - par[0]*par[4] + par[1]; + else if (x > xb) + return par[4]*x - par[4]*par[0]-par[4]*par[2]+par[3]*par[2]+par[1]; else - { - //m = ((par[1]+par[3])-par[1])/par[2]; - //q = par[1]-m*par[0]; - return (par[3]/par[2])*x + par[1]-(par[3])/par[2]*par[0]; - } + return par[3]*x - par[3]*par[0]+par[1]; } -double lapseRatePiecewiseThree_withSlope(double x, std::vector & par) +double detrendingLapseRatePiecewise_three(double x, std::vector & par) { //xa (par[0],par[1]), xb-xa = par[2], par[3] is the slope of the middle piece, //par[4] the slope of the first and last piece @@ -160,14 +122,14 @@ double lapseRatePiecewiseThree_withSlope(double x, std::vector & par) double xb = par[2]+par[0]; if (x < par[0]) - return par[4]*x - par[0]*par[4] + par[1]; + return par[4]*x; else if (x > xb) - return par[4]*x - par[4]*par[0]-par[4]*par[2]+par[3]*par[2]+par[1]; + return par[4]*x; else - return par[3]*x - par[3]*par[0]+par[1]; + return par[3]*x; } -double lapseRatePiecewiseFree(double x, std::vector & par) +double lapseRatePiecewise_three_free(double x, std::vector & par) { // the piecewise line is parameterized as follows // the line passes through A(par[0];par[1])and B(par[0]+par[2];...) @@ -199,6 +161,38 @@ double lapseRatePiecewiseFree(double x, std::vector & par) } } +double detrendingLapseRatePiecewise_three_free(double x, std::vector & par) +{ + // the piecewise line is parameterized as follows + // the line passes through A(par[0];par[1])and B(par[0]+par[2];...) + //par [3] is the slope of the middle piece + //par[4] is the first slope. par[5] is the third slope + + // "y = mx + q" piecewise function; + double xb; + par[2] = MAXVALUE(10, par[2]); + // par[2] means the delta between the two quotes. It must be positive. + xb = par[0]+par[2]; + if (x < par[0]) + { + //m = par[4];; + //q = par[1]-m*par[0]; + return par[4]*x; + } + else if (x>xb) + { + //m = par[5]; + //q = m(-par[0]-par[2])+par[3]*par[2]+par[1]; + return (par[4]*par[0]) + (par[3]*par[2]) + par[5]*(x-xb); + } + else + { + //m = par[3]; + //q = m*(-par[0]) + par[1]; + return (par[4]*par[0]) + par[3]*(x-par[0]); + } +} + double lapseRatePiecewise_two(double x, std::vector & par) { // the piecewise line is parameterized as follows @@ -218,6 +212,25 @@ double lapseRatePiecewise_two(double x, std::vector & par) } } +double detrendingLapseRatePiecewise_two(double x, std::vector & par) +{ + // the piecewise line is parameterized as follows + // the line passes through A(par[0];par[1]). par[2] is the slope of the first line, par[3] the slope of the second + // "y = mx + q" piecewise function; + if (x < par[0]) + { + //m = par[2]; + //q = -par[2]*par[0]+par[1]; + return par[2]*x; + } + else + { + //m = par[3]: + //q = -par[3]*par[0]+par[1]; + return (par[2]*par[0]) + par[3]*(x-par[0]); + } +} + double functionSum(std::vector&)>>& functions, std::vector& x, std::vector >& par) { double result = 0.0; @@ -235,13 +248,18 @@ double functionLinear(double x, std::vector & par) return par[0] * x; } +double functionLinear_intercept(double x, std::vector & par) +{ + return par[0] * x + par[1]; +} + double multilinear(std::vector &x, std::vector &par) { if (par.size() != (x.size()+1)) return NODATA; double y = 0; - for (int i=0; i < x.size(); i++) + for (int i=0; i < int(x.size()); i++) y += par[i] * x[i]; y += par[x.size()]; @@ -724,7 +742,7 @@ namespace interpolation double* parametersDelta, double* parametersChange) { int i, j, k; - double pivot, mult, top; + double mult, top; if (nrParameters <= 0) return; @@ -754,7 +772,7 @@ namespace interpolation for (j = 0; j < nrData; j++) { double newEst = estimateFunction(idFunction, parameters, nrParameters, x[j]); - P[i][j] = (newEst - firstEst[j]) / MAXVALUE(parametersDelta[i], EPSILON) ; + P[i][j] = (newEst - firstEst[j]) / std::max(parametersDelta[i], EPSILON); } parameters[i] -= parametersDelta[i]; } @@ -769,7 +787,7 @@ namespace interpolation a[i][j] += P[i][k] * P[j][k]; } } - z[i] = sqrt(a[i][i]) + EPSILON; //? + z[i] = sqrt(a[i][i]) + EPSILON; } for (i = 0; i < nrParameters; i++) @@ -797,7 +815,7 @@ namespace interpolation for (j = 0; j < (nrParameters - 1); j++) { - pivot = a[j][j]; + double pivot = std::max(a[j][j], EPSILON); for (i = j + 1 ; i < nrParameters; i++) { mult = a[i][j] / pivot; @@ -818,7 +836,8 @@ namespace interpolation { top -= a[i][k] * parametersChange[k]; } - parametersChange[i] = top / a[i][i]; + double pivot = std::max(a[i][i], EPSILON); + parametersChange[i] = top / pivot; } for (i = 0; i < nrParameters; i++) @@ -947,6 +966,112 @@ namespace interpolation } + /*! + * \brief Computes daily values starting from monthly averages using cubic spline + * \param monthlyAvg: vector of monthly averages (12 values) + * outputDailyValues: vector of interpolated daily values (366 values) + */ + void cubicSplineYearInterpolate(float *monthlyAvg, float *outputDailyValues) + { + double monthMid [16] = {-61, - 31, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 396}; + + for (int iMonth=0; iMonth<16; iMonth++) + { + monthMid[iMonth] += 15; + } + + double* avgMonthlyAmountLarger = new double[16]; + for (int iMonth = 0; iMonth < 12; iMonth++) + { + avgMonthlyAmountLarger[iMonth+2] = double(monthlyAvg[iMonth]); + } + + avgMonthlyAmountLarger[0] = double(monthlyAvg[10]); + avgMonthlyAmountLarger[1] = double(monthlyAvg[11]); + avgMonthlyAmountLarger[14] = double(monthlyAvg[0]); + avgMonthlyAmountLarger[15] = double(monthlyAvg[1]); + + for (int iDay=0; iDay<365; iDay++) + { + outputDailyValues[iDay] = float(interpolation::cubicSpline(iDay, monthMid, avgMonthlyAmountLarger, 16)); + } + // leap years + outputDailyValues[365] = outputDailyValues[0]; + + delete [] avgMonthlyAmountLarger; + } + + + /*! + * \brief Computes daily values starting from monthly mean + * using quadratic spline + * original Campbell function + * it has a discontinuity between end and start of the year + */ + void quadrSplineYearInterpolate(float *meanY, float *dayVal) + { + float a[13] = {0}; + float b[14] = {0}; + float c[13] = {0}; + float aa[13] = {0}; + float bb[13] = {0}; + float cc[13] = {0}; + float d[14] = {0}; + float h[13] = {0}; + + int i,j; + + int monthLastDoy [13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; + + d[1] = meanY[0] - meanY[11]; + h[0] = 30; + + for (i = 1; i<=12; i++) + { + if (i == 12) + d[i + 1] = meanY[0] - meanY[i-1]; + else + d[i + 1] = meanY[i] - meanY[i-1]; + + h[i] = float(monthLastDoy[i] - monthLastDoy[i - 1] - 1); + aa[i] = h[i - 1] / 6; + bb[i] = (h[i - 1] + h[i]) / 3; + cc[i] = h[i] / 6; + } + + for (i = 1; i<= 11; i++) + { + cc[i] = cc[i] / bb[i]; + d[i] = d[i] / bb[i]; + bb[i + 1] = bb[i + 1] - aa[i + 1] * cc[i]; + d[i + 1] = d[i + 1] - aa[i + 1] * d[i]; + } + + b[12] = d[12] / bb[12]; + for (i = 11; i>=1; i--) + b[i] = d[i] - cc[i] * b[i + 1]; + + for (i = 1; i<=12; i++) + { + a[i] = (b[i + 1] - b[i]) / (2 * h[i]); + c[i] = meanY[i-1] - (b[i + 1] + 2 * b[i]) * h[i] / 6; + } + + j = 0; + for (i = 1; i<=365; i++) + { + if (monthLastDoy[j] < i) + j = j + 1; + int t = i - monthLastDoy[j - 1] - 1; + + dayVal[i-1] = c[j] + b[j] * t + a[j] * t * t; + + } + + dayVal[365] = dayVal[0]; + } + + double cubicSpline(double x, double *firstColumn, double *secondColumn, int dim) { double a,b,c,d,y; @@ -1052,13 +1177,13 @@ namespace interpolation double meanObs=0; double RSS=0; double TSS=0; - for (int i=0;i (nrPredictors+1)) + if (int(observed.size()) > (nrPredictors+1)) standardError = sqrt(sum_weighted_squared_residuals/(observed.size()-nrPredictors-1)); else standardError = sqrt(sum_weighted_squared_residuals/(observed.size()-1)); @@ -1157,22 +1282,25 @@ namespace interpolation std::vector >& parameters, std::vector >& parametersDelta, int maxIterationsNr, double myEpsilon, double deltaR2, std::vector >& x ,std::vector& y, - std::vector& weights) + std::vector& weights, unsigned int elevationPos) { int i,j; - int nrPredictors = parameters.size(); - int nrData = y.size(); - std::vector nrParameters(nrPredictors); + int nrPredictors = 0; + for (int k = 0; k < parameters.size(); k++) + if (parameters[k].size() == 2) nrPredictors++; + if (elevationPos != NODATA) nrPredictors++; + int nrData = int(y.size()); + std::vector nrParameters(parameters.size()); int nrParametersTotal = 0; - for (i=0; i> bestParameters(nrPredictors); + std::vector > bestParameters(parameters.size()); std::vector > correspondenceTag(2,std::vector(nrParametersTotal)); int counterTag = 0; - for (i=0; i ySim(nrData); int counter = 0; - //srand (unsigned(time(nullptr))); - std::random_device rd; - std::mt19937 gen(rd()); - std::normal_distribution normal_dis(0.5, 0.5); - double truncNormal; + //grigliato - do - { - fittingMarquardt_nDimension_noSquares(func,myFunc,parametersMin, parametersMax, - parameters, parametersDelta,correspondenceTag, maxIterationsNr, - myEpsilon, x, y, weights); + const int numSteps = 20; + std::vector stepSize = {2*(parametersMax[0][0]-parametersMin[0][0])/numSteps, 2*(parametersMax[0][1]-parametersMin[0][1])/numSteps}; - for (i=0;i> firstGuessParam = parameters; + bool exitFlag = 0; - if (R2 > (bestR2-deltaR2)) + for (int step = 1; step <= numSteps; ++step) + { + for (int dir = 0; dir < 2; ++dir) { - for (j=0;j (bestR2)) + for (int proxyIndex = 0; proxyIndex < nrPredictors; ++proxyIndex) { - for (i=0;i= 1.0); - parameters[i][j] = parametersMin[i][j] + (truncNormal)*(parametersMax[i][j]-parametersMin[i][j]); - } - } - } while( (counter < nrTrials) && !(R2Previous[0] > 0.8 && R2Previous[nrMinima-1] > 0.8) && (fabs(R2Previous[0]-R2Previous[nrMinima-1]) > deltaR2) ); + for (i=0;i (bestR2-deltaR2)) + { + for (j=0;j (bestR2)) + { + for (i=0;i proxyIndex && !parameters[proxyIndex].empty()) + { + if (dir == 0) + parameters[proxyIndex][paramIndex] = MINVALUE(firstGuessParam[proxyIndex][paramIndex] + directions[dir] * step * stepSize[paramIndex], parametersMax[proxyIndex][paramIndex]); + else + parameters[proxyIndex][paramIndex] = MAXVALUE(firstGuessParam[proxyIndex][paramIndex] + directions[dir] * step * stepSize[paramIndex], parametersMin[proxyIndex][paramIndex]); + } - for (i=0;i nrTrials) || ((R2Previous[0] != NODATA) && fabs(R2Previous[0]-R2Previous[nrMinima-1]) < deltaR2 )) + { + for (i=0;i& weights) { int i; - int nrPredictors = parameters.size(); - int nrData = y.size(); + int nrPredictors = 0; + for (int k = 0; k < parameters.size(); k++) + if (parameters[k].size() == 2) nrPredictors++; + int nrData = int(y.size()); double mySSE, diffSSE, newSSE; static double VFACTOR = 10; std::vector nrParameters(nrPredictors); @@ -1859,7 +2014,7 @@ namespace interpolation double error; double norm = 0; - for (int i = 0; i < y.size(); i++) + for (int i = 0; i < int(y.size()); i++) { error = y[i] - func(myFunc,x[i], parameters); norm += error * error * weights[i] * weights[i]; @@ -1885,61 +2040,73 @@ namespace interpolation double R2; std::vector R2Previous(nrMinima,NODATA); std::vector ySim(nrData); - int counter = 0; - //srand (unsigned(time(nullptr))); - std::random_device rd; - std::mt19937 gen(rd()); - std::normal_distribution normal_dis(0.5, 0.5); - double truncNormal; - do - { - fittingMarquardt_nDimension_noSquares_singleFunction(func,parametersMin, - parametersMax,parameters, - parametersDelta,maxIterationsNr, - myEpsilon,x,y,weights); + //grigliato + std::vector stepSize; + const int numSteps = 30; + if (parameters.size() == 4) + stepSize = {2*(parametersMax[0]-parametersMin[0])/numSteps, 2*(parametersMax[1]-parametersMin[1])/numSteps, 20*(parametersMax[2]-parametersMin[2])/numSteps, 20*(parametersMax[3]-parametersMin[3])/numSteps}; + else if (parameters.size() == 6) + stepSize = {2*(parametersMax[0]-parametersMin[0])/numSteps, 2*(parametersMax[1]-parametersMin[1])/numSteps, 4*(parametersMax[2]-parametersMin[2])/numSteps, 20*(parametersMax[3]-parametersMin[3])/numSteps,20*(parametersMax[3]-parametersMin[3])/numSteps,20*(parametersMax[3]-parametersMin[3])/numSteps }; + else return false; - for (i=0;i firstGuessParam = parameters; - if (R2 > (bestR2-deltaR2)) + for (int step = 1; step <= numSteps; ++step) + { + for (int dir = 0; dir < 2; ++dir) { - for (j=0;j (bestR2)) - { - for (j=0; j (bestR2-deltaR2)) + { + for (j=0;j (bestR2)) + { + for (j=0; j= 1.0); - parameters[j] = parametersMin[j] + (truncNormal)*(parametersMax[j]-parametersMin[j]); - } - } while( (counter < nrTrials) && (R2 < 0.8) && (fabs(R2Previous[0]-R2Previous[nrMinima-1]) > deltaR2) ); + if ((counter > nrTrials) || ((R2Previous[0] != NODATA) && fabs(R2Previous[0]-R2Previous[nrMinima-1]) < deltaR2 )) + break; + } for (j=0; j= 0; i--) { @@ -2061,7 +2227,7 @@ namespace interpolation { top -= a[i][k] * paramChange[k]; } - paramChange[i] = top / a[i][i]; + paramChange[i] = top / std::max(a[i][i], EPSILON); } // change parameters diff --git a/agrolib/mathFunctions/furtherMathFunctions.h b/agrolib/mathFunctions/furtherMathFunctions.h index 60940f42..0b9aa663 100644 --- a/agrolib/mathFunctions/furtherMathFunctions.h +++ b/agrolib/mathFunctions/furtherMathFunctions.h @@ -48,15 +48,22 @@ enum estimatedFunction {FUNCTION_CODE_SPHERICAL, FUNCTION_CODE_LINEAR, FUNCTION_ double functionSum(std::vector &)> > &functions, std::vector& x, std::vector >& par); double functionSum_detrending(std::vector&)>>& functions, std::vector x, std::vector >& par); double functionLinear(double x, std::vector & par); - double lapseRatePiecewise_three(double x, std::vector & par); - double lapseRatePiecewiseForInterpolation(double x, std::vector & par); - double lapseRatePiecewiseFree(double x, std::vector & par); - double lapseRatePiecewiseThree_withSlope(double x, std::vector & par); - double lapseRatePiecewise_two(double x, std::vector & par); + double functionLinear_intercept(double x, std::vector & par); + double multilinear(std::vector &x, std::vector &par); double lapseRateFrei(double x, std::vector & par); double lapseRateFreiFree(double x, std::vector & par); double lapseRateRotatedSigmoid(double x, std::vector par); + double lapseRatePiecewise_two(double x, std::vector & par); + double lapseRatePiecewise_three_noSlope(double x, std::vector & par); + double lapseRatePiecewise_three(double x, std::vector & par); + double lapseRatePiecewise_three_free(double x, std::vector & par); + + double detrendingLapseRatePiecewise_two(double x, std::vector & par); + double detrendingLapseRatePiecewise_three(double x, std::vector & par); + double detrendingLapseRatePiecewise_three_free(double x, std::vector & par); + + namespace integration { float trapzdParametric(float (*func)(TfunctionInput), int nrPar, float *par , float a , float b , int n); @@ -91,7 +98,10 @@ enum estimatedFunction {FUNCTION_CODE_SPHERICAL, FUNCTION_CODE_LINEAR, FUNCTION_ double normGeneric(int idFunction, double *parameters, int nrParameters, double *x, double *y, int nrData); double modifiedVanGenuchten(double psi, double *parameters, bool isRestricted); - double cubicSpline(double x , double *firstColumn , double *secondColumn, int dim); // not working to be checked + double cubicSpline(double x , double *firstColumn , double *secondColumn, int dim); + void cubicSplineYearInterpolate(float *monthlyAvg, float *outputDailyValues); + void quadrSplineYearInterpolate(float *meanY, float *dayVal); + bool punctualSecondDerivative(int dim, double *firstColumn , double *secondColumn, double* secondDerivative); // not working to be checked void tridiagonalThomasAlgorithm (int n, double *subDiagonal, double *mainDiagonal, double *superDiagonal, double *constantTerm, double* output); // not working to be checked @@ -105,7 +115,7 @@ enum estimatedFunction {FUNCTION_CODE_SPHERICAL, FUNCTION_CODE_LINEAR, FUNCTION_ std::vector > ¶metersMin, std::vector > ¶metersMax, std::vector > ¶meters, std::vector > ¶metersDelta, int maxIterationsNr, double myEpsilon, double deltaR2, - std::vector >& x , std::vector& y, std::vector& weights); + std::vector >& x , std::vector& y, std::vector& weights, unsigned int elevationPos); bool fittingMarquardt_nDimension(double (*func)(std::vector &)> > &, std::vector &, std::vector >&), std::vector &)> > &myFunc, diff --git a/agrolib/mathFunctions/statistics.cpp b/agrolib/mathFunctions/statistics.cpp index 51b99143..2ee6f098 100644 --- a/agrolib/mathFunctions/statistics.cpp +++ b/agrolib/mathFunctions/statistics.cpp @@ -42,7 +42,7 @@ float statisticalElab(meteoComputation elab, float param, std::vector val switch(elab) { case average: - return statistics::mean(values, nValues); + return statistics::mean(values); case maxInList: return statistics::maxList(values, nValues); case minInList: @@ -246,7 +246,7 @@ namespace statistics { if (measured.size() != simulated.size()) return NODATA; - float obsAvg = mean(measured, int(measured.size())); + float obsAvg = mean(measured); if (isEqual(obsAvg, NODATA)) return NODATA; @@ -1102,7 +1102,7 @@ namespace statistics if (nrList <= 1) return NODATA; - myMean = mean(myList,nrList); + myMean = mean(myList); squareDiff = 0; nrValidValues = 0; @@ -1129,7 +1129,7 @@ namespace statistics if (nrList <= 1) return NODATA; - myMean = mean(myList,nrList); + myMean = mean(myList); squareDiff = 0; nrValidValues = 0; @@ -1199,52 +1199,54 @@ namespace statistics return NODATA; } - float mean(std::vector myList, int nrList) + + float mean(std::vector list) { - float sum=0.; - int i, nrValidValues; + if (list.size() < 1) + return NODATA; - if (nrList < 1) return NODATA; - nrValidValues = 0; + int nrValidValues = 0; + double sum = 0.; - for (i = 0; i < nrList; i++) + for (int i = 0; i < list.size(); i++) { - if (myList[i]!= NODATA) + if (! isEqual(list[i], NODATA)) { - sum += myList[i]; + sum += double(list[i]); nrValidValues++; } } - if (nrValidValues > 0) - return (sum/(float)(nrValidValues)); - else + if (nrValidValues == 0) return NODATA; + + return float(sum / double(nrValidValues)); } - double mean(std::vector myList, int nrList) + + double mean(std::vector list) { - double sum=0.; - int i, nrValidValues; + if (list.size() < 1) return NODATA; - if (nrList < 1) return NODATA; - nrValidValues = 0; + int nrValidValues = 0; + double sum=0; - for (i = 0; i < nrList; i++) + for (int i = 0; i < int(list.size()); i++) { - if (myList[i]!= NODATA) + if (list[i] != NODATA) { - sum += myList[i]; + sum += list[i]; nrValidValues++; } } if (nrValidValues > 0) - return (sum/(double)(nrValidValues)); + return (sum / (double)(nrValidValues)); else return NODATA; } + double mean(double *myList, int nrList) { double sum=0.; diff --git a/agrolib/mathFunctions/statistics.h b/agrolib/mathFunctions/statistics.h index 530a9d93..fcc6f102 100644 --- a/agrolib/mathFunctions/statistics.h +++ b/agrolib/mathFunctions/statistics.h @@ -48,8 +48,8 @@ double variance(std::vector myList, int nrList); double variance(double *myList, int nrList); float mean(float *myList, int nrList); - float mean(std::vector myList, int nrList); - double mean(std::vector myList, int nrList); + float mean(std::vector list); + double mean(std::vector list); double mean(double *myList, int nrList); float covariance(float *myList1, int nrList1,float *myList2, int nrList2); double covariance(double *myList1, int nrList1,double *myList2, int nrList2); diff --git a/agrolib/meteo/meteo.cpp b/agrolib/meteo/meteo.cpp index 53c327c1..df096947 100644 --- a/agrolib/meteo/meteo.cpp +++ b/agrolib/meteo/meteo.cpp @@ -786,6 +786,12 @@ bool setColorScale(meteoVariable variable, Crit3DColorScale *colorScale) case snowFall: case snowWaterEquivalent: case snowLiquidWaterContent: case snowMelt: case dailyWaterTableDepth: setPrecipitationScale(colorScale); + if (variable == snowFall || variable == snowWaterEquivalent + || variable == snowLiquidWaterContent || variable == snowMelt) + { + colorScale->setHideOutliers(true); + colorScale->setTransparent(true); + } break; case snowAge: setGrayScale(colorScale); @@ -921,6 +927,10 @@ std::string getVariableString(meteoVariable myVar) else if (myVar == leafAreaIndex) return "Leaf area index (m2 m-2)"; + else if (myVar == elaboration) + return "Elaboration"; + else if (myVar == anomaly) + return "Anomaly"; else if (myVar == noMeteoTerrain) return "Elevation (m)"; else @@ -944,9 +954,9 @@ std::string getKeyStringMeteoMap(std::map map, meteo return key; } + std::string getUnitFromVariable(meteoVariable var) { - std::string unit = ""; std::map, std::string>::const_iterator it; std::vector key; @@ -961,9 +971,11 @@ std::string getUnitFromVariable(meteoVariable var) } key.clear(); } + return unit; } + meteoVariable getKeyMeteoVarMeteoMap(std::map map, const std::string& value) { std::map::const_iterator it; diff --git a/agrolib/meteo/meteo.h b/agrolib/meteo/meteo.h index 648778fa..31279554 100644 --- a/agrolib/meteo/meteo.h +++ b/agrolib/meteo/meteo.h @@ -108,7 +108,7 @@ enum criteria3DVariable {volumetricWaterContent, waterTotalPotential, waterMatricPotential, availableWaterContent, degreeOfSaturation, soilTemperature, soilSurfaceMoisture, bottomDrainage, waterDeficit, waterInflow, waterOutflow, - factorOfSafety}; + factorOfSafety, minimumFactorOfSafety, surfacePond}; const std::map MapDailyMeteoVar = { diff --git a/agrolib/meteo/meteoGrid.cpp b/agrolib/meteo/meteoGrid.cpp index 26af6a75..3e688159 100644 --- a/agrolib/meteo/meteoGrid.cpp +++ b/agrolib/meteo/meteoGrid.cpp @@ -988,7 +988,7 @@ void Crit3DMeteoGrid::saveRowColfromZone(gis::Crit3DRasterGrid* zoneGrid, std::v double utmX = x; double utmY = y; gis::getLatLonFromUtm(_gisSettings, utmX, utmY, &y, &x); - gis::getGridRowColFromXY(_gridStructure.header(), x, y, &myRow, &myCol); + gis::getGridRowColFromLonLat(_gridStructure.header(), x, y, &myRow, &myCol); } else { diff --git a/agrolib/meteo/meteoPoint.cpp b/agrolib/meteo/meteoPoint.cpp index ab3908d1..9dd857d9 100644 --- a/agrolib/meteo/meteoPoint.cpp +++ b/agrolib/meteo/meteoPoint.cpp @@ -709,7 +709,7 @@ void Crit3DMeteoPoint::cleanObsDataM() bool Crit3DMeteoPoint::setMeteoPointValueH(const Crit3DDate& myDate, int myHour, int myMinutes, meteoVariable myVar, float myValue) { - //check + // check if (myVar == noMeteoVar || obsDataH == nullptr) { return false; @@ -718,13 +718,13 @@ bool Crit3DMeteoPoint::setMeteoPointValueH(const Crit3DDate& myDate, int myHour, // day index int i = obsDataH[0].date.daysTo(myDate); - //check if out of range (accept +1 date exceed) + // check if out of range (accept +1 date exceed) if (i < 0 || i > nrObsDataDaysH) return false; // sub hourly index int subH = int(ceil(float(myMinutes) / float(60 / hourlyFraction))); - //if +1 date exceed accept only hour 00:00 + // if +1 date exceed accept only hour 00:00 if (i == nrObsDataDaysH && (myHour != 0 || subH != 0)) return false; // hour 0 becomes hour 24 of the previous day @@ -1326,7 +1326,7 @@ bool Crit3DMeteoPoint::getDailyDataCsv_TPrec(std::string &outStr) outStr = "Date, Tmin (C), Tmax (C), Tavg (C), Prec (mm)\n"; std::ostringstream valueStream; - for (int i = 0; i < obsDataD.size(); i++) + for (int i = 0; i < int(obsDataD.size()); i++) { // Date outStr += obsDataD[i].date.toStdString() + ","; diff --git a/agrolib/meteo/quality.h b/agrolib/meteo/quality.h index c6de84c7..aadb5362 100644 --- a/agrolib/meteo/quality.h +++ b/agrolib/meteo/quality.h @@ -28,8 +28,7 @@ class Range { private: - float _max; - float _min; + float _min, _max; public: Range() { _min = NODATA; _max = NODATA; } diff --git a/agrolib/meteoWidget/dialogMeteoTable.cpp b/agrolib/meteoWidget/dialogMeteoTable.cpp index cfc30f94..7bafccb0 100644 --- a/agrolib/meteoWidget/dialogMeteoTable.cpp +++ b/agrolib/meteoWidget/dialogMeteoTable.cpp @@ -31,7 +31,6 @@ DialogMeteoTable::DialogMeteoTable(Crit3DMeteoSettings *meteoSettings_, QVector< QVBoxLayout* mainLayout = new QVBoxLayout; this->resize(800, 600); - meteoTable = new MeteoTable(); mainLayout->addWidget(meteoTable); diff --git a/agrolib/meteoWidget/meteoWidget.cpp b/agrolib/meteoWidget/meteoWidget.cpp index 17f19dee..5324411c 100644 --- a/agrolib/meteoWidget/meteoWidget.cpp +++ b/agrolib/meteoWidget/meteoWidget.cpp @@ -1,24 +1,29 @@ /*! - CRITERIA3D - \copyright 2016 Fausto Tomei, Gabriele Antolini, Laura Costantini - Alberto Pistocchi, Marco Bittelli, Antonio Volta - You should have received a copy of the GNU General Public License - along with Nome-Programma. If not, see . + \file meteoWidget.cpp + + \abstract this widget displays hourly or daily weather data sets + + \copyright This file is part of CRITERIA3D. - CRITERIA3D has been developed under contract issued by A.R.P.A. Emilia-Romagna + CRITERIA3D has been developed by ARPAE Emilia-Romagna. + CRITERIA3D is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + CRITERIA3D 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 Lesser General Public License for more details. - You should have received a copy of the /NU Lesser General Public License + + You should have received a copy of the GNU Lesser General Public License along with CRITERIA3D. If not, see . - contacts: - fausto.tomei@gmail.com - ftomei@arpae.it + + \authors + Laura Costantini + Fausto Tomei ftomei@arpae.it + Gabriele Antolini gantolini@arpae.it */ @@ -59,7 +64,7 @@ Crit3DMeteoWidget::Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMe this->resize(1240, 700); this->setAttribute(Qt::WA_DeleteOnClose); - currentFreq = noFrequency; + _currentFrequency = noFrequency; QDate noDate = QDate(1800,1,1); currentDate = noDate; @@ -117,7 +122,7 @@ Crit3DMeteoWidget::Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMe currentVariables.clear(); QTextStream in(&fileDefaultGraph); in.readLine(); //skip first line - while (!in.atEnd()) + while (! in.atEnd()) { QString line = in.readLine(); QList items = line.split(","); @@ -135,11 +140,11 @@ Crit3DMeteoWidget::Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMe } if (key.contains("DAILY")) { - currentFreq = daily; + _currentFrequency = daily; } else { - currentFreq = hourly; + _currentFrequency = hourly; } MapCSVDefault.insert(key,items); zeroLine = new QLineSeries(); @@ -198,10 +203,11 @@ Crit3DMeteoWidget::Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMe hourlyVar = hourlyVar+1; } } + if (currentVariables.isEmpty() || (dailyVar != 0 && hourlyVar != 0)) { QMessageBox::information(nullptr, "Warning", "Wrong variables in Crit3DPlotDefault.csv"); - currentFreq = noFrequency; + _currentFrequency = noFrequency; currentVariables.clear(); nameLines.clear(); nameBar.clear(); @@ -287,19 +293,19 @@ Crit3DMeteoWidget::Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMe firstDate->setMinimumWidth(firstDate->width()-firstDate->width()*0.3); lastDate->setMinimumWidth(lastDate->width()-lastDate->width()*0.3); - if (currentFreq == daily || currentFreq == noFrequency) + if (_currentFrequency == daily || _currentFrequency == noFrequency) { dailyButton->setEnabled(false); hourlyButton->setEnabled(true); monthlyButton->setEnabled(true); } - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) { hourlyButton->setEnabled(false); dailyButton->setEnabled(true); monthlyButton->setEnabled(true); } - else if (currentFreq == monthly) + else if (_currentFrequency == monthly) { monthlyButton->setEnabled(false); dailyButton->setEnabled(true); @@ -326,23 +332,23 @@ Crit3DMeteoWidget::Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMe axisX = new QBarCategoryAxis(); axisXvirtual = new QBarCategoryAxis(); - axisY = new QValueAxis(); - axisYdx = new QValueAxis(); + axisY_sx = new QValueAxis(); + axisY_dx = new QValueAxis(); axisX->setTitleText("Date"); axisXvirtual->setTitleText("Date"); axisXvirtual->setGridLineVisible(false); - axisY->setRange(0,30); - axisY->setGridLineVisible(false); + axisY_sx->setRange(0,30); + axisY_sx->setGridLineVisible(false); - axisYdx->setRange(0,8); - axisYdx->setGridLineVisible(false); + axisY_dx->setRange(0,8); + axisY_dx->setGridLineVisible(false); chart->addAxis(axisX, Qt::AlignBottom); chart->addAxis(axisXvirtual, Qt::AlignBottom); - chart->addAxis(axisY, Qt::AlignLeft); - chart->addAxis(axisYdx, Qt::AlignRight); + chart->addAxis(axisY_sx, Qt::AlignLeft); + chart->addAxis(axisY_dx, Qt::AlignRight); chart->legend()->setVisible(true); chart->legend()->setAlignment(Qt::AlignBottom); @@ -415,20 +421,46 @@ Crit3DMeteoWidget::~Crit3DMeteoWidget() } -void Crit3DMeteoWidget::setDateIntervalDaily(QDate firstDate, QDate lastDate) +void Crit3DMeteoWidget::setFrequency(frequencyType frequency) +{ + _currentFrequency = frequency; + + // update gui + if (_currentFrequency == daily || _currentFrequency == noFrequency) + { + dailyButton->setEnabled(false); + hourlyButton->setEnabled(true); + monthlyButton->setEnabled(true); + } + else if (_currentFrequency == hourly) + { + hourlyButton->setEnabled(false); + dailyButton->setEnabled(true); + monthlyButton->setEnabled(true); + } + else if (_currentFrequency == monthly) + { + monthlyButton->setEnabled(false); + dailyButton->setEnabled(true); + hourlyButton->setEnabled(true); + } +} + + +void Crit3DMeteoWidget::setDailyRange(QDate firstDate, QDate lastDate) { firstDailyDate = firstDate; lastDailyDate = lastDate; } -void Crit3DMeteoWidget::setDateIntervalHourly(QDate firstDate, QDate lastDate) +void Crit3DMeteoWidget::setHourlyRange(QDate firstDate, QDate lastDate) { firstHourlyDate = firstDate; lastHourlyDate = lastDate; } -void Crit3DMeteoWidget::setDateIntervalMonthly(QDate firstDate, QDate lastDate) +void Crit3DMeteoWidget::setMonthlyRange(QDate firstDate, QDate lastDate) { firstMonthlyDate = firstDate; lastMonthlyDate = lastDate; @@ -499,9 +531,11 @@ void Crit3DMeteoWidget::updateTimeRange() lastMonthlyDate = myMonthlyDateLast; } } + checkExistingData(); } + void Crit3DMeteoWidget::checkExistingData() { // set enable/disable buttons if daily/hourly/monthly data are available @@ -548,11 +582,11 @@ void Crit3DMeteoWidget::drawMeteoPoint(Crit3DMeteoPoint mp, bool isAppend) lastDate->setDate(currentDate); // draw period (31 days for daily, 3 days for hourly) - if (currentFreq == daily) + if (_currentFrequency == daily) { firstDate->setDate(currentDate.addDays(-30)); } - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) { firstDate->setDate(currentDate.addDays(-2)); } @@ -628,13 +662,16 @@ void Crit3DMeteoWidget::drawEnsemble() { lastDailyDate = myDailyDateLast; } + myHourlyDateFirst.setDate(meteoPointsEnsemble[0].getMeteoPointHourlyValuesDate(0).year, meteoPointsEnsemble[0].getMeteoPointHourlyValuesDate(0).month, meteoPointsEnsemble[0].getMeteoPointHourlyValuesDate(0).day); myHourlyDateLast = myHourlyDateFirst.addDays(meteoPointsEnsemble[0].nrObsDataDaysH-1); + if (myHourlyDateFirst.isValid() && myHourlyDateFirst < firstHourlyDate) { firstHourlyDate = myHourlyDateFirst; } + if (myHourlyDateLast.isValid() && myHourlyDateLast > lastHourlyDate) { lastHourlyDate = myHourlyDateLast; @@ -643,9 +680,9 @@ void Crit3DMeteoWidget::drawEnsemble() lastDate->setDate(currentDate); // draw period (31 days for daily, 3 days for hourly) - if (currentFreq == daily) + if (_currentFrequency == daily) firstDate->setDate(currentDate.addDays(-30)); - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) firstDate->setDate(currentDate.addDays(-2)); redraw(); @@ -926,7 +963,7 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() categories.append(QString::number(day)); } - QList sortedList; + std::vector sortedList; QList listBoxSet; if (isLine) @@ -952,7 +989,7 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() double value = meteoPointsEnsemble[mp].getMeteoPointValueD(myDate, meteoVar, meteoSettings); if (value != NODATA) { - sortedList.append(value); + sortedList.push_back(value); if (value > maxEnsembleLine) { maxEnsembleLine = value; @@ -964,15 +1001,15 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() } } QBoxSet *box = new QBoxSet(); - if (!sortedList.isEmpty()) + if (! sortedList.empty()) { std::sort(sortedList.begin(), sortedList.end()); - int count = sortedList.count(); - box->setValue(QBoxSet::LowerExtreme, sortedList.first()); - box->setValue(QBoxSet::UpperExtreme, sortedList.last()); - box->setValue(QBoxSet::Median, findMedian(sortedList, 0, count)); - box->setValue(QBoxSet::LowerQuartile, findMedian(sortedList, 0, count / 2)); - box->setValue(QBoxSet::UpperQuartile, findMedian(sortedList, count / 2 + (count % 2), count)); + int lastIndex = int(sortedList.size())-1; + box->setValue(QBoxSet::LowerExtreme, sortedList.front()); + box->setValue(QBoxSet::UpperExtreme, sortedList.back()); + box->setValue(QBoxSet::Median, findMedian(sortedList, 0, lastIndex)); + box->setValue(QBoxSet::LowerQuartile, findMedian(sortedList, 0, lastIndex / 2)); + box->setValue(QBoxSet::UpperQuartile, findMedian(sortedList, lastIndex / 2 + (lastIndex % 2), lastIndex)); } else { @@ -992,7 +1029,7 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() ensembleSeries.append(series); chart->addSeries(series); series->attachAxis(axisX); - series->attachAxis(axisY); + series->attachAxis(axisY_sx); } } } @@ -1019,7 +1056,7 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() double value = meteoPointsEnsemble[mp].getMeteoPointValueD(myDate, meteoVar, meteoSettings); if (value != NODATA) { - sortedList.append(value); + sortedList.push_back(value); if (value > maxEnsembleBar) { maxEnsembleBar = value; @@ -1027,15 +1064,15 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() } } QBoxSet *box = new QBoxSet(); - if (!sortedList.isEmpty()) + if (! sortedList.empty()) { std::sort(sortedList.begin(), sortedList.end()); - int count = sortedList.count(); - box->setValue(QBoxSet::LowerExtreme, sortedList.first()); - box->setValue(QBoxSet::UpperExtreme, sortedList.last()); - box->setValue(QBoxSet::Median, findMedian(sortedList, 0, count)); - box->setValue(QBoxSet::LowerQuartile, findMedian(sortedList, 0, count / 2)); - box->setValue(QBoxSet::UpperQuartile, findMedian(sortedList, count / 2 + (count % 2), count)); + int lastIndex = int(sortedList.size())-1; + box->setValue(QBoxSet::LowerExtreme, sortedList.front()); + box->setValue(QBoxSet::UpperExtreme, sortedList.back()); + box->setValue(QBoxSet::Median, findMedian(sortedList, 0, lastIndex)); + box->setValue(QBoxSet::LowerQuartile, findMedian(sortedList, 0, lastIndex / 2)); + box->setValue(QBoxSet::UpperQuartile, findMedian(sortedList, lastIndex / 2 + (lastIndex % 2), lastIndex)); } else { @@ -1055,7 +1092,7 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() ensembleSeries.append(series); chart->addSeries(series); series->attachAxis(axisX); - series->attachAxis(axisYdx); + series->attachAxis(axisY_dx); } } } @@ -1064,62 +1101,123 @@ void Crit3DMeteoWidget::drawEnsembleDailyVar() { if (maxEnsembleLine == NODATA && minEnsembleLine == -NODATA) { - axisY->setVisible(false); + axisY_sx->setVisible(false); } else { - axisY->setVisible(true); - axisY->setMax(maxEnsembleLine); - axisY->setMin(minEnsembleLine); - if (axisY->max() == axisY->min()) + axisY_sx->setVisible(true); + axisY_sx->setMax(maxEnsembleLine); + axisY_sx->setMin(minEnsembleLine); + if (axisY_sx->max() == axisY_sx->min()) { - axisY->setRange(axisY->min()-axisY->min()/100, axisY->max()+axisY->max()/100); + axisY_sx->setRange(axisY_sx->min()-axisY_sx->min()/100, axisY_sx->max()+axisY_sx->max()/100); } } } else { - axisY->setVisible(false); + axisY_sx->setVisible(false); } if (isBar) { if (maxEnsembleBar == -1) { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } else { - axisYdx->setVisible(true); + axisY_dx->setVisible(true); if (maxEnsembleBar != 0) { - axisYdx->setRange(0,maxEnsembleBar); + axisY_dx->setRange(0,maxEnsembleBar); } else { - axisYdx->setRange(0,1); + axisY_dx->setRange(0,1); } } } else { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } axisX->setCategories(categories); axisXvirtual->setCategories(categoriesVirtual); axisXvirtual->setGridLineVisible(false); + drawAxisTitle(); + formInfo.close(); + firstDate->blockSignals(false); lastDate->blockSignals(false); +} - formInfo.close(); + +void Crit3DMeteoWidget::drawAxisTitle() +{ + if (! isInitialized) + return; + + QList unitList; + QString axisTitle = ""; + + // axis sx (lines) + for (int i = 0; i < nameLines.size(); i++) + { + meteoVariable meteoVar = getMeteoVar(nameLines[i].toStdString()); + QString unitStr = QString::fromStdString(getUnitFromVariable(meteoVar)); + if (! unitList.contains(unitStr)) + { + unitList.append(unitStr); + } + } + + if (! unitList.empty()) + { + for (int i = 0; i < unitList.size(); i++) + { + if (i > 0) + axisTitle += " , "; + + axisTitle += unitList[i]; + } + } + axisY_sx->setTitleText(axisTitle); + + // axis dx (bar) + unitList.clear(); + for (int i = 0; i < nameBar.size(); i++) + { + meteoVariable meteoVar = getMeteoVar(nameBar[i].toStdString()); + QString unitStr = QString::fromStdString(getUnitFromVariable(meteoVar)); + if (! unitList.contains(unitStr)) + { + unitList.append(unitStr); + } + } + + axisTitle.clear(); + if (! unitList.empty()) + { + for (int i = 0; i < unitList.size(); i++) + { + if (i > 0) + axisTitle += " , "; + + axisTitle += unitList[i]; + } + } + + axisY_dx->setTitleText(axisTitle); } void Crit3DMeteoWidget::drawDailyVar() { - if (! isInitialized) return; + if (! isInitialized) + return; FormInfo formInfo; formInfo.showInfo("Draw daily data..."); @@ -1202,7 +1300,8 @@ void Crit3DMeteoWidget::drawDailyVar() { if (meteoPoints[mp].isDateLoadedD(myDate)) { - lineSeries[mp][i]->append(day, value); // nodata days are not drawed if they are the first of the last day of the serie + // nodata days are not drawed if they are the first of the last day of the series + lineSeries[mp][i]->append(day, value); } } } @@ -1254,33 +1353,33 @@ void Crit3DMeteoWidget::drawDailyVar() { chart->addSeries(barSeries[mp]); barSeries[mp]->attachAxis(axisX); - barSeries[mp]->attachAxis(axisYdx); + barSeries[mp]->attachAxis(axisY_dx); } } if (maxEnsembleBar == -1 && maxBar == -1) { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } else { - axisYdx->setVisible(true); + axisY_dx->setVisible(true); if (maxEnsembleBar > maxBar) { - axisYdx->setRange(0,maxEnsembleBar); + axisY_dx->setRange(0,maxEnsembleBar); } else { - axisYdx->setRange(0,maxBar); + axisY_dx->setRange(0,maxBar); } - if (axisYdx->max() == axisYdx->min()) + if (axisY_dx->max() == axisY_dx->min()) { - axisYdx->setRange(0,1); + axisY_dx->setRange(0,1); } } } else { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } if (isLine) @@ -1293,7 +1392,7 @@ void Crit3DMeteoWidget::drawDailyVar() { chart->addSeries(lineSeries[mp][i]); lineSeries[mp][i]->attachAxis(axisX); - lineSeries[mp][i]->attachAxis(axisY); + lineSeries[mp][i]->attachAxis(axisY_sx); connect(lineSeries[mp][i], &QLineSeries::hovered, this, &Crit3DMeteoWidget::tooltipLineSeries); connect(lineSeries[mp][i], &QLineSeries::clicked, this, &Crit3DMeteoWidget::editLineSeries); } @@ -1301,41 +1400,41 @@ void Crit3DMeteoWidget::drawDailyVar() } if (maxLine == NODATA && minLine == -NODATA && maxEnsembleLine == NODATA && minEnsembleLine == -NODATA) { - axisY->setVisible(false); + axisY_sx->setVisible(false); } else { - axisY->setVisible(true); + axisY_sx->setVisible(true); if (maxEnsembleLine > maxLine) { - axisY->setMax(maxEnsembleLine); + axisY_sx->setMax(maxEnsembleLine); } else { - axisY->setMax(maxLine); + axisY_sx->setMax(maxLine); } if (minEnsembleLine < minLine) { - axisY->setMin(minEnsembleLine); + axisY_sx->setMin(minEnsembleLine); } else { - axisY->setMin(minLine); + axisY_sx->setMin(minLine); } - if (axisY->max() == axisY->min()) + if (axisY_sx->max() == axisY_sx->min()) { - axisY->setRange(axisY->min()-axisY->min()/100, axisY->max()+axisY->max()/100); + axisY_sx->setRange(axisY_sx->min()-axisY_sx->min()/100, axisY_sx->max()+axisY_sx->max()/100); } } } else { - axisY->setVisible(false); + axisY_sx->setVisible(false); } // add zeroLine - if (axisY->min() <= 0 && axisY->max() >= 0) + if (axisY_sx->min() <= 0 && axisY_sx->max() >= 0) { zeroLine->clear(); for (int day = 0; day < nDays; day++) @@ -1344,7 +1443,7 @@ void Crit3DMeteoWidget::drawDailyVar() } chart->addSeries(zeroLine); zeroLine->attachAxis(axisX); - zeroLine->attachAxis(axisY); + zeroLine->attachAxis(axisY_sx); } // add minimimum values required @@ -1405,7 +1504,7 @@ void Crit3DMeteoWidget::drawDailyVar() } } - + drawAxisTitle(); formInfo.close(); } @@ -1556,29 +1655,29 @@ void Crit3DMeteoWidget::drawHourlyVar() { chart->addSeries(barSeries[mp]); barSeries[mp]->attachAxis(axisX); - barSeries[mp]->attachAxis(axisYdx); + barSeries[mp]->attachAxis(axisY_dx); } } if (maxBar == -1) { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } else { - axisYdx->setVisible(true); + axisY_dx->setVisible(true); if (maxBar != 0) { - axisYdx->setRange(0,maxBar); + axisY_dx->setRange(0,maxBar); } else { - axisYdx->setRange(0,1); + axisY_dx->setRange(0,1); } } } else { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } if (isLine) @@ -1589,34 +1688,34 @@ void Crit3DMeteoWidget::drawHourlyVar() { chart->addSeries(lineSeries[mp][i]); lineSeries[mp][i]->attachAxis(axisX); - lineSeries[mp][i]->attachAxis(axisY); + lineSeries[mp][i]->attachAxis(axisY_sx); connect(lineSeries[mp][i], &QLineSeries::hovered, this, &Crit3DMeteoWidget::tooltipLineSeries); connect(lineSeries[mp][i], &QLineSeries::clicked, this, &Crit3DMeteoWidget::editLineSeries); } } if (maxLine == NODATA && minLine == -NODATA) { - axisY->setVisible(false); + axisY_sx->setVisible(false); } else { - axisY->setVisible(true); - axisY->setMax(maxLine); - axisY->setMin(minLine); + axisY_sx->setVisible(true); + axisY_sx->setMax(maxLine); + axisY_sx->setMin(minLine); - if (axisY->max() == axisY->min()) + if (axisY_sx->max() == axisY_sx->min()) { - axisY->setRange(axisY->min()-axisY->min()/100, axisY->max()+axisY->max()/100); + axisY_sx->setRange(axisY_sx->min()-axisY_sx->min()/100, axisY_sx->max()+axisY_sx->max()/100); } } } else { - axisY->setVisible(false); + axisY_sx->setVisible(false); } // add zeroLine - if (axisY->min() <= 0 && axisY->max() >= 0) + if (axisY_sx->min() <= 0 && axisY_sx->max() >= 0) { zeroLine->clear(); for (int d = 0; d < nDays; d++) @@ -1629,7 +1728,7 @@ void Crit3DMeteoWidget::drawHourlyVar() } chart->addSeries(zeroLine); zeroLine->attachAxis(axisX); - zeroLine->attachAxis(axisY); + zeroLine->attachAxis(axisY_sx); } axisX->setCategories(categories); @@ -1654,9 +1753,11 @@ void Crit3DMeteoWidget::drawHourlyVar() } } + drawAxisTitle(); formInfo.close(); } + void Crit3DMeteoWidget::drawMonthlyVar() { if (! isInitialized) return; @@ -1791,33 +1892,33 @@ void Crit3DMeteoWidget::drawMonthlyVar() { chart->addSeries(barSeries[mp]); barSeries[mp]->attachAxis(axisX); - barSeries[mp]->attachAxis(axisYdx); + barSeries[mp]->attachAxis(axisY_dx); } } if (maxEnsembleBar == -1 && maxBar == -1) { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } else { - axisYdx->setVisible(true); + axisY_dx->setVisible(true); if (maxEnsembleBar > maxBar) { - axisYdx->setRange(0,maxEnsembleBar); + axisY_dx->setRange(0,maxEnsembleBar); } else { - axisYdx->setRange(0,maxBar); + axisY_dx->setRange(0,maxBar); } - if (axisYdx->max() == axisYdx->min()) + if (axisY_dx->max() == axisY_dx->min()) { - axisYdx->setRange(0,1); + axisY_dx->setRange(0,1); } } } else { - axisYdx->setVisible(false); + axisY_dx->setVisible(false); } if (isLine) @@ -1830,7 +1931,7 @@ void Crit3DMeteoWidget::drawMonthlyVar() { chart->addSeries(lineSeries[mp][i]); lineSeries[mp][i]->attachAxis(axisX); - lineSeries[mp][i]->attachAxis(axisY); + lineSeries[mp][i]->attachAxis(axisY_sx); connect(lineSeries[mp][i], &QLineSeries::hovered, this, &Crit3DMeteoWidget::tooltipLineSeries); connect(lineSeries[mp][i], &QLineSeries::clicked, this, &Crit3DMeteoWidget::editLineSeries); } @@ -1838,41 +1939,41 @@ void Crit3DMeteoWidget::drawMonthlyVar() } if (maxLine == NODATA && minLine == -NODATA && maxEnsembleLine == NODATA && minEnsembleLine == -NODATA) { - axisY->setVisible(false); + axisY_sx->setVisible(false); } else { - axisY->setVisible(true); + axisY_sx->setVisible(true); if (maxEnsembleLine > maxLine) { - axisY->setMax(maxEnsembleLine); + axisY_sx->setMax(maxEnsembleLine); } else { - axisY->setMax(maxLine); + axisY_sx->setMax(maxLine); } if (minEnsembleLine < minLine) { - axisY->setMin(minEnsembleLine); + axisY_sx->setMin(minEnsembleLine); } else { - axisY->setMin(minLine); + axisY_sx->setMin(minLine); } - if (axisY->max() == axisY->min()) + if (axisY_sx->max() == axisY_sx->min()) { - axisY->setRange(axisY->min()-axisY->min()/100, axisY->max()+axisY->max()/100); + axisY_sx->setRange(axisY_sx->min()-axisY_sx->min()/100, axisY_sx->max()+axisY_sx->max()/100); } } } else { - axisY->setVisible(false); + axisY_sx->setVisible(false); } // add zeroLine - if (axisY->min() <= 0 && axisY->max() >= 0) + if (axisY_sx->min() <= 0 && axisY_sx->max() >= 0) { zeroLine->clear(); for (int month = 0; month < numberOfMonths; month++) @@ -1881,7 +1982,7 @@ void Crit3DMeteoWidget::drawMonthlyVar() } chart->addSeries(zeroLine); zeroLine->attachAxis(axisX); - zeroLine->attachAxis(axisY); + zeroLine->attachAxis(axisY_sx); } // add minimimum values required @@ -1942,6 +2043,7 @@ void Crit3DMeteoWidget::drawMonthlyVar() } } + drawAxisTitle(); formInfo.close(); } @@ -1950,19 +2052,19 @@ void Crit3DMeteoWidget::showVar() { if (! isInitialized) return; - if (currentFreq == noFrequency) + if (_currentFrequency == noFrequency) { if (dailyButton->isChecked()) // dailyButton is pressed { - currentFreq = daily; + _currentFrequency = daily; } else if (hourlyButton->isChecked()) { - currentFreq = hourly; + _currentFrequency = hourly; } else if (monthlyButton->isChecked()) { - currentFreq = monthly; + _currentFrequency = monthly; } } QList allKeys = MapCSVStyles.keys(); @@ -1970,21 +2072,21 @@ void Crit3DMeteoWidget::showVar() QList allVar; for (int i = 0; idate().daysTo(lastDate->date()); QDate firstValidDate; - if (currentFreq == daily) + if (_currentFrequency == daily) { if (! firstDailyDate.isValid() || firstDailyDate.year() == 1800) return; firstValidDate = firstDailyDate; } - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) { if (! firstHourlyDate.isValid() || firstHourlyDate.year() == 1800) return; firstValidDate = firstHourlyDate; } - else if (currentFreq == monthly) + else if (_currentFrequency == monthly) { if (! firstMonthlyDate.isValid() || firstMonthlyDate.year() == 1800) return; @@ -2376,7 +2477,7 @@ void Crit3DMeteoWidget::shiftFollowing() int nDays = firstDate->date().daysTo(lastDate->date()); QDate lastValidDate; - if (currentFreq == daily) + if (_currentFrequency == daily) { if (! lastDailyDate.isValid() || lastDailyDate.year() == 1800) return; @@ -2408,7 +2509,7 @@ void Crit3DMeteoWidget::shiftFollowing() void Crit3DMeteoWidget::showTable() { - DialogMeteoTable meteoTable(meteoSettings, meteoPoints, firstDate->date(), lastDate->date(), currentFreq, currentVariables); + DialogMeteoTable meteoTable(meteoSettings, meteoPoints, firstDate->date(), lastDate->date(), _currentFrequency, currentVariables); } void Crit3DMeteoWidget::tooltipLineSeries(QPointF point, bool state) @@ -2507,18 +2608,18 @@ bool Crit3DMeteoWidget::computeTooltipLineSeries(QLineSeries *series, QPointF po if (!valueExist) { // missing data - if (currentFreq == daily) + if (_currentFrequency == daily) { QDate xDate = firstDate->date().addDays(doy); m_tooltip->setText(QString("%1 \n%2 nan ").arg(series->name()).arg(xDate.toString("MMM dd yyyy"))); } - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) { QDateTime xDate(firstDate->date(), QTime(0,0,0), Qt::UTC); xDate = xDate.addSecs(3600*doy); m_tooltip->setText(QString("%1 \n%2 nan ").arg(series->name()).arg(xDate.toString("MMM dd yyyy hh:mm"))); } - else if (currentFreq == monthly) + else if (_currentFrequency == monthly) { QDate xDate = firstDate->date().addMonths(doy); m_tooltip->setText(QString("%1 \n%2 nan ").arg(series->name()).arg(xDate.toString("MMM yyyy"))); @@ -2638,7 +2739,7 @@ bool Crit3DMeteoWidget::computeTooltipLineSeries(QLineSeries *series, QPointF po } - if (currentFreq == daily) + if (_currentFrequency == daily) { QDate xDate = firstDate->date().addDays(doy); for(int i = 0; i < series->count(); i++) @@ -2652,7 +2753,7 @@ bool Crit3DMeteoWidget::computeTooltipLineSeries(QLineSeries *series, QPointF po double value = series->at(doyRelative).y(); m_tooltip->setText(QString("%1 \n%2 %3 ").arg(series->name()).arg(xDate.toString("MMM dd yyyy")).arg(value, 0, 'f', 1)); } - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) { QDateTime xDate(firstDate->date(), QTime(0,0,0), Qt::UTC); xDate = xDate.addSecs(3600*doy); @@ -2667,7 +2768,7 @@ bool Crit3DMeteoWidget::computeTooltipLineSeries(QLineSeries *series, QPointF po double value = series->at(doyRelative).y(); m_tooltip->setText(QString("%1 \n%2 %3 ").arg(series->name()).arg(xDate.toString("MMM dd yyyy hh:mm")).arg(value, 0, 'f', 1)); } - else if (currentFreq == monthly) + else if (_currentFrequency == monthly) { QDate xDate = firstDate->date().addMonths(doy); for(int i = 0; i < series->count(); i++) @@ -2728,19 +2829,19 @@ void Crit3DMeteoWidget::tooltipBar(bool state, int index, QBarSet *barset) } QString valueStr; - if (currentFreq == daily) + if (_currentFrequency == daily) { QDate xDate = firstDate->date().addDays(index); valueStr = QString("%1 \n%2 %3 ").arg(xDate.toString("MMM dd yyyy")).arg(barset->label()).arg(barset->at(index), 0, 'f', 1); } - else if (currentFreq == hourly) + else if (_currentFrequency == hourly) { QDateTime xDate(firstDate->date(), QTime(0,0,0), Qt::UTC); xDate = xDate.addSecs(3600*index); valueStr = QString("%1 \n%2 %3 ").arg(xDate.toString("MMM dd yyyy hh:mm")).arg(barset->label()).arg(barset->at(index), 0, 'f', 1); } - else if (currentFreq == monthly) + else if (_currentFrequency == monthly) { QDate xDate = firstDate->date().addMonths(index); valueStr = QString("%1 \n%2 %3 ").arg(xDate.toString("MMM yyyy")).arg(barset->label()).arg(barset->at(index), 0, 'f', 1); @@ -2895,49 +2996,25 @@ void Crit3DMeteoWidget::setIsEnsemble(bool value) tableButton->setEnabled(!value); } -bool Crit3DMeteoWidget::getIsEnsemble() -{ - return isEnsemble; -} - -void Crit3DMeteoWidget::setNrMembers(int value) -{ - nrMembers = value; -} - -int Crit3DMeteoWidget::getMeteoWidgetID() const -{ - return meteoWidgetID; -} - -void Crit3DMeteoWidget::setMeteoWidgetID(int value) -{ - meteoWidgetID = value; -} - -void Crit3DMeteoWidget::setCurrentDate(QDate myDate) -{ - currentDate = myDate; -} void Crit3DMeteoWidget::on_actionChangeLeftAxis() { - DialogChangeAxis changeAxisDialog(true); + DialogChangeAxis changeAxisDialog(1, false); if (changeAxisDialog.result() == QDialog::Accepted) { - axisY->setMax(changeAxisDialog.getMaxVal()); - axisY->setMin(changeAxisDialog.getMinVal()); + axisY_sx->setMax(changeAxisDialog.getMaxVal()); + axisY_sx->setMin(changeAxisDialog.getMinVal()); } } void Crit3DMeteoWidget::on_actionChangeRightAxis() { - DialogChangeAxis changeAxisDialog(false); + DialogChangeAxis changeAxisDialog(2, false); if (changeAxisDialog.result() == QDialog::Accepted) { - axisYdx->setMax(changeAxisDialog.getMaxVal()); - axisYdx->setMin(changeAxisDialog.getMinVal()); + axisY_dx->setMax(changeAxisDialog.getMaxVal()); + axisY_dx->setMin(changeAxisDialog.getMinVal()); } } @@ -3206,7 +3283,7 @@ void Crit3DMeteoWidget::drawSum() cumulativePoints.clear(); } } - axisY->setRange(axisY->min(),max); + axisY_sx->setRange(axisY_sx->min(),max); } } if (! barSeries.isEmpty()) @@ -3238,24 +3315,24 @@ void Crit3DMeteoWidget::drawSum() cumulativeValues.clear(); } } - axisYdx->setRange(axisYdx->min(),max); + axisY_dx->setRange(axisY_dx->min(),max); } } } } -qreal findMedian(QList sortedList, int begin, int end) +qreal findMedian(std::vector sortedList, int begin, int end) { int count = end - begin; - if (count % 2) { + if (count % 2) + { return sortedList.at(count / 2 + begin); - } else { + } + else + { qreal right = sortedList.at(count / 2 + begin); qreal left = sortedList.at(count / 2 - 1 + begin); return (right + left) / 2.0; } } - - - diff --git a/agrolib/meteoWidget/meteoWidget.h b/agrolib/meteoWidget/meteoWidget.h index 39c878c0..d27e6c62 100644 --- a/agrolib/meteoWidget/meteoWidget.h +++ b/agrolib/meteoWidget/meteoWidget.h @@ -7,8 +7,6 @@ #include "meteoPoint.h" #include "callout.h" - qreal findMedian(QList sortedList, int begin, int end); - class Crit3DMeteoWidget : public QWidget { Q_OBJECT @@ -17,55 +15,26 @@ Crit3DMeteoWidget(bool isGrid_, QString projectPath, Crit3DMeteoSettings* meteoSettings_); ~Crit3DMeteoWidget() override; - int getMeteoWidgetID() const; - void setMeteoWidgetID(int value); + int getMeteoWidgetID() const { return meteoWidgetID; } + void setMeteoWidgetID(int value) { meteoWidgetID = value; } + + void setCurrentDate(QDate myDate) { currentDate = myDate; } + + void setIsEnsemble(bool value); + bool getIsEnsemble() { return isEnsemble; } + void setNrMembers(int value) { nrMembers = value; } + + void setFrequency(frequencyType frequency); - void setCurrentDate(QDate myDate); - void setDateIntervalDaily(QDate firstDate, QDate lastDate); - void setDateIntervalHourly(QDate firstDate, QDate lastDate); - void setDateIntervalMonthly(QDate firstDate, QDate lastDate); + void setDailyRange(QDate firstDate, QDate lastDate); + void setHourlyRange(QDate firstDate, QDate lastDate); + void setMonthlyRange(QDate firstDate, QDate lastDate); void addMeteoPointsEnsemble(Crit3DMeteoPoint mp); - void updateTimeRange(); void drawMeteoPoint(Crit3DMeteoPoint mp, bool isAppend); void drawEnsemble(); - void resetValues(); - void resetEnsembleValues(); - void drawDailyVar(); - void drawEnsembleDailyVar(); - void drawHourlyVar(); - void drawMonthlyVar(); - void showMonthlyGraph(); - void showDailyGraph(); - void showHourlyGraph(); - void updateSeries(); - void redraw(); - void shiftPrevious(); - void shiftFollowing(); - void showTable(); - void showVar(); - void tooltipLineSeries(QPointF point, bool state); - void editLineSeries(); - bool computeTooltipLineSeries(QLineSeries *series, QPointF point, bool state); - void tooltipBar(bool state, int index, QBarSet *barset); - void editBar(); - void handleMarkerClicked(); - void closeEvent(QCloseEvent *event) override; - void setIsEnsemble(bool value); - bool getIsEnsemble(); - void setNrMembers(int value); - void on_actionChangeLeftAxis(); - void on_actionChangeRightAxis(); - void on_actionExportGraph(); - void on_actionRemoveStation(); - void on_actionInfoPoint(); - void on_actionDataAvailability(); - void on_actionDataSum(); - void drawSum(); - void checkExistingData(); - private: int meteoWidgetID; bool isGrid; @@ -77,7 +46,7 @@ QVector meteoPointsEnsemble; Crit3DMeteoSettings* meteoSettings; - frequencyType currentFreq; + frequencyType _currentFrequency; QDate firstDailyDate; QDate lastDailyDate; QDate firstHourlyDate; @@ -101,8 +70,8 @@ QChart *chart; QBarCategoryAxis *axisX; QBarCategoryAxis *axisXvirtual; - QValueAxis *axisY; - QValueAxis *axisYdx; + QValueAxis *axisY_sx; + QValueAxis *axisY_dx; QMap> MapCSVDefault; QMap> MapCSVStyles; QList currentVariables; @@ -128,6 +97,44 @@ bool isLine; bool isBar; Callout *m_tooltip; + + void updateTimeRange(); + void resetValues(); + void resetEnsembleValues(); + void drawDailyVar(); + void drawEnsembleDailyVar(); + void drawHourlyVar(); + void drawMonthlyVar(); + void showMonthlyGraph(); + void showDailyGraph(); + void showHourlyGraph(); + void updateSeries(); + void redraw(); + void shiftPrevious(); + void shiftFollowing(); + void showTable(); + void showVar(); + void tooltipLineSeries(QPointF point, bool state); + void editLineSeries(); + bool computeTooltipLineSeries(QLineSeries *series, QPointF point, bool state); + void tooltipBar(bool state, int index, QBarSet *barset); + void editBar(); + void handleMarkerClicked(); + void closeEvent(QCloseEvent *event) override; + + void on_actionChangeLeftAxis(); + void on_actionChangeRightAxis(); + void on_actionExportGraph(); + void on_actionRemoveStation(); + void on_actionInfoPoint(); + void on_actionDataAvailability(); + void on_actionDataSum(); + + void drawAxisTitle(); + void drawSum(); + void checkExistingData(); + + signals: void closeWidgetPoint(int); void closeWidgetGrid(int); @@ -135,4 +142,7 @@ }; + qreal findMedian(std::vector sortedList, int begin, int end); + + #endif // METEOWIDGET_H diff --git a/agrolib/netcdfHandler/netcdfHandler.cpp b/agrolib/netcdfHandler/netcdfHandler.cpp index 5873288c..3fa6e50a 100644 --- a/agrolib/netcdfHandler/netcdfHandler.cpp +++ b/agrolib/netcdfHandler/netcdfHandler.cpp @@ -1307,8 +1307,3 @@ bool NetCDFHandler::extractVariableMap(int idVar, const Crit3DTime &myTime, std: return true; } - -gis::Crit3DRasterGrid* NetCDFHandler::getRaster() -{ - return &dataGrid; -} diff --git a/agrolib/netcdfHandler/netcdfHandler.h b/agrolib/netcdfHandler/netcdfHandler.h index 20e7ec44..4e32e7dd 100644 --- a/agrolib/netcdfHandler/netcdfHandler.h +++ b/agrolib/netcdfHandler/netcdfHandler.h @@ -95,7 +95,7 @@ NetCDFVariable getVariableFromId(int idVar); NetCDFVariable getVariableFromIndex(int index); - gis::Crit3DRasterGrid* getRaster(); + gis::Crit3DRasterGrid* getRasterPointer() { return &dataGrid; } bool readProperties(std::string fileName); bool exportDataSeries(int idVar, gis::Crit3DGeoPoint geoPoint, Crit3DTime seriesFirstTime, Crit3DTime seriesLastTime, std::stringstream *buffer); diff --git a/agrolib/outputPoints/dbOutputPointsHandler.cpp b/agrolib/outputPoints/dbOutputPointsHandler.cpp index 08a7cd47..636add04 100644 --- a/agrolib/outputPoints/dbOutputPointsHandler.cpp +++ b/agrolib/outputPoints/dbOutputPointsHandler.cpp @@ -13,14 +13,10 @@ Crit3DOutputPointsDbHandler::Crit3DOutputPointsDbHandler(QString dbname_) { _db.close(); } - errorString = ""; _db = QSqlDatabase::addDatabase("QSQLITE", QUuid::createUuid().toString()); _db.setDatabaseName(dbname_); - if (! _db.open()) - { - errorString = _db.lastError().text(); - } + _db.open(); } @@ -97,23 +93,26 @@ bool Crit3DOutputPointsDbHandler::addCriteria3DColumn(const QString &tableName, } // column name - QString newField = variableString + "_" + QString::number(depth); + if (depth != NODATA) + { + variableString += "_" + QString::number(depth); + } // column exists already QList fieldList = getFields(&_db, tableName); - if ( fieldList.contains(newField) ) + if ( fieldList.contains(variableString) ) { return true; } // add column QString queryString = "ALTER TABLE '" + tableName + "'"; - queryString += " ADD " + newField + " REAL"; + queryString += " ADD " + variableString + " REAL"; QSqlQuery myQuery = _db.exec(queryString); if (myQuery.lastError().isValid()) { - errorStr = "Error in add column: " + newField + "\n" + myQuery.lastError().text(); + errorStr = "Error in add column: " + variableString + "\n" + myQuery.lastError().text(); return false; } @@ -123,26 +122,78 @@ bool Crit3DOutputPointsDbHandler::addCriteria3DColumn(const QString &tableName, bool Crit3DOutputPointsDbHandler::saveHourlyMeteoData(const QString &tableName, const QDateTime &myTime, const std::vector &varList, - const std::vector &values, + const std::vector &valuesList, QString &errorStr) { - if (varList.size() != values.size()) + if (varList.size() != valuesList.size()) { errorStr = "Error saving values: number of variables is different from values"; return false; } - QSqlQuery qry(_db); QString timeStr = myTime.toString("yyyy-MM-dd HH:mm:ss"); - QString queryString = QString("DELETE FROM '%1' WHERE DATE_TIME ='%2'").arg(tableName, timeStr); + QString queryString = QString("SELECT * FROM '%1' WHERE DATE_TIME='%2'").arg(tableName, timeStr); + QSqlQuery query(_db); + if (! query.exec(queryString)) + { + errorStr = QString("Error in reading table: %1 \nTime: %2 \n%3") + .arg(tableName, timeStr, query.lastError().text()); + return false; + } + + query.last(); + int querySize = query.at() + 1; // SQLITE doesn't support SIZE + if (querySize > 0) + { + return saveHourlyMeteoData_update(tableName, timeStr, varList, valuesList, errorStr); + } + else + { + return saveHourlyMeteoData_insert(tableName, timeStr, varList, valuesList, errorStr); + } + +} + + +bool Crit3DOutputPointsDbHandler::saveHourlyMeteoData_update(const QString &tableName, const QString timeStr, + const std::vector &varList, + const std::vector &values, + QString &errorStr) +{ + QList assignList; + for (unsigned int i = 0; i < varList.size(); i++) + { + QString fieldStr = QString::fromStdString(getMeteoVarName(varList[i])); + if (fieldStr.isEmpty()) + { + errorStr = QString("Error saving values in table:%1 \nMissing variable name").arg(tableName); + return false; + } + + QString valueStr = QString::number(values[i], 'f', 2); + + assignList.push_back("'" + fieldStr + "'=" + valueStr); + } + + QSqlQuery qry(_db); + QString queryString = QString("UPDATE '%1' SET %2 WHERE DATE_TIME = DATETIME('%3')").arg(tableName, assignList.join(','), timeStr); if (! qry.exec(queryString)) { - errorStr = QString("Error deleting values in table:%1 Time:%2\n%3") - .arg(tableName, timeStr, qry.lastError().text()); + errorStr = QString("Error saving values in table:%1 Time:%2\n%3") + .arg(tableName, timeStr, qry.lastError().text()); return false; } + return true; +} + + +bool Crit3DOutputPointsDbHandler::saveHourlyMeteoData_insert(const QString &tableName, const QString timeStr, + const std::vector &varList, + const std::vector &values, + QString &errorStr) +{ // field list QString fieldList = "'DATE_TIME'"; for (unsigned int i = 0; i < varList.size(); i++) @@ -154,23 +205,24 @@ bool Crit3DOutputPointsDbHandler::saveHourlyMeteoData(const QString &tableName, } else { - errorStr = "Error saving values: missing variable name."; + errorStr = QString("Error saving values in table:%1 \nMissing variable name").arg(tableName); return false; } } // values list QString valuesList = "'" + timeStr + "'"; - for (unsigned int i = 0; i < varList.size(); i++) + for (unsigned int i = 0; i < values.size(); i++) { valuesList += "," + QString::number(values[i], 'f', 2); } - queryString = QString("INSERT INTO '%1' (%2) VALUES (%3)").arg(tableName, fieldList, valuesList); + QSqlQuery qry(_db); + QString queryString = QString("INSERT INTO '%1' (%2) VALUES (%3)").arg(tableName, fieldList, valuesList); if (! qry.exec(queryString)) { errorStr = QString("Error saving values in table:%1 Time:%2\n%3") - .arg(tableName, timeStr, qry.lastError().text()); + .arg(tableName, timeStr, qry.lastError().text()); return false; } @@ -178,22 +230,20 @@ bool Crit3DOutputPointsDbHandler::saveHourlyMeteoData(const QString &tableName, } -// layerDepth [m] + +// variableDepth [cm] bool Crit3DOutputPointsDbHandler::saveHourlyCriteria3D_Data(const QString &tableName, const QDateTime& myTime, - const std::vector& varList, - const std::vector& values, - const std::vector & layerDepth, - QString &errorStr) + const std::vector& values, + const std::vector& waterContentDepth, + const std::vector& waterPotentialDepth, + const std::vector& degreeOfSaturationDepth, + const std::vector& factorOfSafetyDepth, + QString &errorStr) { - int nrSoilLayers = int(layerDepth.size()) - 1; - if (nrSoilLayers <= 0) - { - errorStr = "Error saving values: missing soil layers."; - return false; - } + int nrValues = int(waterContentDepth.size() + waterPotentialDepth.size() + + degreeOfSaturationDepth.size() + factorOfSafetyDepth.size()); - int nrValues = int(varList.size()) * nrSoilLayers; - if (nrValues != values.size()) + if (nrValues != int(values.size())) { errorStr = "Error saving values: number of values is not as expected."; return false; @@ -201,35 +251,16 @@ bool Crit3DOutputPointsDbHandler::saveHourlyCriteria3D_Data(const QString &table QString timeStr = myTime.toString("yyyy-MM-dd HH:mm:ss"); - // field list - QString setList = ""; - for (unsigned int i = 0; i < varList.size(); i++) - { - QString variableString = QString::fromStdString(getCriteria3DVarName(varList[i])); - if (variableString == "") - { - errorStr = "Missing variable name."; - return false; - } - - for (int layer = 1; layer <= nrSoilLayers; layer++) - { - int depth = round(layerDepth[layer] * 100); // [cm] + QList valueList; + int firstIndex = 0; + appendCriteria3DOutputValue(volumetricWaterContent, waterContentDepth, values, firstIndex, valueList); + appendCriteria3DOutputValue(waterMatricPotential, waterPotentialDepth, values, firstIndex, valueList); + appendCriteria3DOutputValue(degreeOfSaturation, degreeOfSaturationDepth, values, firstIndex, valueList); + appendCriteria3DOutputValue(factorOfSafety, factorOfSafetyDepth, values, firstIndex, valueList); - QString fieldName = variableString + "_" + QString::number(depth); - setList += "'" + fieldName + "'="; - - int index = i * nrSoilLayers + layer - 1; - QString valueStr = QString::number(values[index], 'f', 2); - setList += valueStr; - - if (index < (nrValues - 1)) - setList += ","; - } - } QSqlQuery qry(_db); - QString queryString = QString("UPDATE '%1' SET %2 WHERE DATE_TIME ='%3'").arg(tableName, setList, timeStr); + QString queryString = QString("UPDATE '%1' SET %2 WHERE DATE_TIME = DATETIME('%3')").arg(tableName, valueList.join(','), timeStr); if (! qry.exec(queryString)) { errorStr = QString("Error in query: " + queryString + "\n" + qry.lastError().text()); @@ -239,3 +270,26 @@ bool Crit3DOutputPointsDbHandler::saveHourlyCriteria3D_Data(const QString &table return true; } + +void Crit3DOutputPointsDbHandler::appendCriteria3DOutputValue(criteria3DVariable myVar, const std::vector &depthList, + const std::vector& values, int &firstIndex, + QList &outputList) +{ + QString variableString = QString::fromStdString(getCriteria3DVarName(myVar)); + + for (int l = 0; l < depthList.size(); l++) + { + float depth_cm = depthList[l]; + QString fieldName = variableString + "_" + QString::number(depth_cm); + + int index = firstIndex + l; + QString valueStr = QString::number(values[index], 'f', 3); + + QString assignStr = "'" + fieldName + "'=" + valueStr; + + outputList.push_back(assignStr); + } + + firstIndex += int(depthList.size()); +} + diff --git a/agrolib/outputPoints/dbOutputPointsHandler.h b/agrolib/outputPoints/dbOutputPointsHandler.h index 00742d1f..7007fbab 100644 --- a/agrolib/outputPoints/dbOutputPointsHandler.h +++ b/agrolib/outputPoints/dbOutputPointsHandler.h @@ -6,6 +6,7 @@ #endif #include + #include #include class Crit3DOutputPointsDbHandler @@ -14,14 +15,14 @@ explicit Crit3DOutputPointsDbHandler(QString dbname_); ~Crit3DOutputPointsDbHandler(); - QString getDbName() { - return _db.databaseName(); } + QString getDbName() + { return _db.databaseName(); } - QString getErrorString() { - return errorString; } + QString getErrorString() + { return _db.lastError().text(); } - bool isOpen() { - return _db.isOpen(); } + bool isOpen() + { return _db.isOpen(); } bool createTable(const QString &tableName, QString &errorStr); @@ -31,16 +32,33 @@ bool saveHourlyMeteoData(const QString &tableName, const QDateTime &myTime, const std::vector &varList, - const std::vector &values, QString &errorStr); + const std::vector &valuesList, QString &errorStr); - bool saveHourlyCriteria3D_Data(const QString &tableName, const QDateTime &myTime, - const std::vector &varList, - const std::vector &values, - const std::vector &layerDepth, QString &errorStr); + bool saveHourlyCriteria3D_Data(const QString &tableName, const QDateTime& myTime, + const std::vector& values, + const std::vector& waterContentDepth, + const std::vector& waterPotentialDepth, + const std::vector& degreeOfSaturationDepth, + const std::vector& factorOfSafetyDepth, + QString &errorStr); + + void appendCriteria3DOutputValue(criteria3DVariable myVar, const std::vector &depthList, + const std::vector& values, int &firstIndex, + QList &outputList); private: + QSqlDatabase _db; - QString errorString; + + bool saveHourlyMeteoData_insert(const QString &tableName, const QString timeStr, + const std::vector &varList, + const std::vector &values, + QString &errorStr); + + bool saveHourlyMeteoData_update(const QString &tableName, const QString timeStr, + const std::vector &varList, + const std::vector &values, + QString &errorStr); }; diff --git a/agrolib/pointStatisticsWidget/dialogElaboration.cpp b/agrolib/pointStatisticsWidget/dialogElaboration.cpp index 706db6c7..c384e4a3 100644 --- a/agrolib/pointStatisticsWidget/dialogElaboration.cpp +++ b/agrolib/pointStatisticsWidget/dialogElaboration.cpp @@ -175,13 +175,9 @@ DialogElaboration::DialogElaboration(QSettings *settings, Crit3DClimate *clima, settings->endGroup(); elaborationLayout.addWidget(&elaborationList); - QLocale local(QLocale::system().language()); - local.setNumberOptions(QLocale::RejectGroupSeparator); elab1Parameter.setPlaceholderText("Parameter"); elab1Parameter.setFixedWidth(90); - QDoubleValidator* validator = new QDoubleValidator(-9999.0, 9999.0, 2); - validator->setLocale(local); - elab1Parameter.setValidator(validator); + elab1Parameter.setValidator(new QDoubleValidator(-9999.0, 9999.0, 2)); QString elab1Field = elaborationList.currentText(); if ( MapElabWithParam.find(elab1Field.toStdString()) == MapElabWithParam.end()) @@ -272,7 +268,7 @@ void DialogElaboration::done(bool res) clima->setElab1(elaborationList.currentText()); clima->setParam1IsClimate(false); - if (elab1Parameter.text() != "") + if (! elab1Parameter.text().isEmpty()) { clima->setParam1(elab1Parameter.text().toFloat()); } diff --git a/agrolib/pointStatisticsWidget/pointStatisticsWidget.cpp b/agrolib/pointStatisticsWidget/pointStatisticsWidget.cpp index a8bf09f9..672bf8ae 100644 --- a/agrolib/pointStatisticsWidget/pointStatisticsWidget.cpp +++ b/agrolib/pointStatisticsWidget/pointStatisticsWidget.cpp @@ -697,7 +697,8 @@ void Crit3DPointStatisticsWidget::plot() double availab = double(validData) / double(count) * 100.0; availability.setText(QString::number(availab, 'f', 3)); - double mkendall = statisticalElab(mannKendall, NODATA, outputValues, outputValues.size(), meteoSettings->getRainfallThreshold()); + double mkendall = statisticalElab(mannKendall, NODATA, outputValues, int(outputValues.size()), + meteoSettings->getRainfallThreshold()); significance.setText(QString::number(mkendall, 'f', 3)); double averageValue = sum / double(validData); average.setText(QString::number(averageValue, 'f', 1)); @@ -707,7 +708,7 @@ void Crit3DPointStatisticsWidget::plot() float myR2 = NODATA; bool isZeroIntercept = false; std::vector yearsFloat(years.begin(), years.end()); - statistics::linearRegression(yearsFloat, outputValues, outputValues.size(), isZeroIntercept, + statistics::linearRegression(yearsFloat, outputValues, int(outputValues.size()), isZeroIntercept, &myIntercept, &myCoeff, &myR2); r2.setText(QString::number(double(myR2), 'f', 3)); rate.setText(QString::number(double(myCoeff), 'f', 3)); @@ -868,7 +869,8 @@ void Crit3DPointStatisticsWidget::plot() float availab = ((float)validData/(float)count)*100.0; availability.setText(QString::number(availab, 'f', 3)); - float mkendall = statisticalElab(mannKendall, NODATA, outputValues, outputValues.size(), meteoSettings->getRainfallThreshold()); + float mkendall = statisticalElab(mannKendall, NODATA, outputValues, int(outputValues.size()), + meteoSettings->getRainfallThreshold()); significance.setText(QString::number(mkendall, 'f', 3)); float averageValue = sum/validYears; average.setText(QString::number(averageValue, 'f', 1)); @@ -878,7 +880,7 @@ void Crit3DPointStatisticsWidget::plot() float myR2 = NODATA; bool isZeroIntercept = false; std::vector yearsFloat(years.begin(), years.end()); - statistics::linearRegression(yearsFloat, outputValues, outputValues.size(), isZeroIntercept, + statistics::linearRegression(yearsFloat, outputValues, int(outputValues.size()), isZeroIntercept, &myIntercept, &myCoeff, &myR2); r2.setText(QString::number(myR2, 'f', 3)); rate.setText(QString::number(myCoeff, 'f', 3)); @@ -1169,10 +1171,10 @@ void Crit3DPointStatisticsWidget::plot() visualizedNrValues = visualizedNrValues + 1; } } - avg = statistics::mean(series, nrValues); + avg = statistics::mean(series); dev_std = statistics::standardDeviation(series, nrValues); - millile3dev = sorting::percentile(sortedSeries, nrValues, 99.73, true); - millile_3Dev = sorting::percentile(sortedSeries, nrValues, 0.27, false); + millile3dev = sorting::percentile(sortedSeries, nrValues, 99.73f, true); + millile_3Dev = sorting::percentile(sortedSeries, nrValues, 0.27f, false); } availability.setText(QString::number((float)nrValues/(float)totDays * 100, 'f', 3)); @@ -1447,10 +1449,10 @@ void Crit3DPointStatisticsWidget::plot() } } } - avg = statistics::mean(series, nrValues); + avg = statistics::mean(series); dev_std = statistics::standardDeviation(series, nrValues); - millile3dev = sorting::percentile(sortedSeries, nrValues, 99.73, true); - millile_3Dev = sorting::percentile(sortedSeries, nrValues, 0.27, false); + millile3dev = sorting::percentile(sortedSeries, nrValues, 99.73f, true); + millile_3Dev = sorting::percentile(sortedSeries, nrValues, 0.27f, false); } availability.setText(QString::number((float)nrValues/(float)totDays * 100, 'f', 3)); average.setText(QString::number(avg, 'f', 1)); @@ -1626,7 +1628,7 @@ void Crit3DPointStatisticsWidget::showElaboration() float availab = ((float)validYears/(float)years.size())*100.0; availability.setText(QString::number(availab, 'f', 3)); - float mkendall = statisticalElab(mannKendall, NODATA, outputValues, outputValues.size(), meteoSettings->getRainfallThreshold()); + float mkendall = statisticalElab(mannKendall, NODATA, outputValues, int(outputValues.size()), meteoSettings->getRainfallThreshold()); significance.setText(QString::number(mkendall, 'f', 3)); float averageValue = sum/validYears; average.setText(QString::number(averageValue, 'f', 1)); @@ -1636,7 +1638,7 @@ void Crit3DPointStatisticsWidget::showElaboration() float myR2 = NODATA; bool isZeroIntercept = false; std::vector yearsFloat(years.begin(), years.end()); - statistics::linearRegression(yearsFloat, outputValues, outputValues.size(), isZeroIntercept, + statistics::linearRegression(yearsFloat, outputValues, int(outputValues.size()), isZeroIntercept, &myIntercept, &myCoeff, &myR2); r2.setText(QString::number(myR2, 'f', 3)); rate.setText(QString::number(myCoeff, 'f', 3)); @@ -1687,7 +1689,7 @@ void Crit3DPointStatisticsWidget::computePlot() void Crit3DPointStatisticsWidget::on_actionChangeLeftAxis() { - DialogChangeAxis changeAxisDialog(true); + DialogChangeAxis changeAxisDialog(1, false); if (changeAxisDialog.result() == QDialog::Accepted) { chartView->setYmax(changeAxisDialog.getMaxVal()); diff --git a/agrolib/pragaProject/dialogMeteoComputation.cpp b/agrolib/pragaProject/dialogMeteoComputation.cpp index 39ddce59..548fa622 100644 --- a/agrolib/pragaProject/dialogMeteoComputation.cpp +++ b/agrolib/pragaProject/dialogMeteoComputation.cpp @@ -275,13 +275,9 @@ DialogMeteoComputation::DialogMeteoComputation(QSettings *settings, bool isMeteo settings->endGroup(); elaborationLayout.addWidget(&elaborationList); - QLocale local(QLocale::system().language()); - local.setNumberOptions(QLocale::RejectGroupSeparator); elab1Parameter.setPlaceholderText("Parameter"); elab1Parameter.setFixedWidth(90); - QDoubleValidator* validator = new QDoubleValidator(-9999.0, 9999.0, 2); - validator->setLocale(local); - elab1Parameter.setValidator(validator); + elab1Parameter.setValidator(new QDoubleValidator(-9999.0, 9999.0, 2)); readParam.setText("Read param from db Climate"); readParam.setChecked(false); climateDbElabList.setVisible(false); @@ -331,7 +327,7 @@ DialogMeteoComputation::DialogMeteoComputation(QSettings *settings, bool isMeteo elab2Parameter.setPlaceholderText("Parameter"); elab2Parameter.setFixedWidth(90); - elab2Parameter.setValidator(validator); + elab2Parameter.setValidator(new QDoubleValidator(-9999.0, 9999.0, 2)); QString elab2Field = secondElabList.currentText(); if ( MapElabWithParam.find(elab2Field.toStdString()) == MapElabWithParam.end()) @@ -567,7 +563,7 @@ void DialogMeteoComputation::done(bool res) if (!readParam.isChecked()) { myProject.clima->setParam1IsClimate(false); - if (elab1Parameter.text() != "") + if (! elab1Parameter.text().isEmpty()) { myProject.clima->setParam1(elab1Parameter.text().toFloat()); } diff --git a/agrolib/pragaProject/pragaProject.cpp b/agrolib/pragaProject/pragaProject.cpp index fcba0433..a50730ba 100644 --- a/agrolib/pragaProject/pragaProject.cpp +++ b/agrolib/pragaProject/pragaProject.cpp @@ -1539,17 +1539,21 @@ bool PragaProject::downloadDailyDataArkimet(QList variables, bool prec0 id = QString::fromStdString(meteoPoints[i].id); dataset = QString::fromStdString(meteoPoints[i].dataset); - if (!datasetList.contains(dataset)) + // if the point doesn't have dataset, it is not downloaded from arkimet + if (! dataset.isEmpty()) { - datasetList << dataset; - QList myList; - myList << id; - idList.append(myList); - } - else - { - index = datasetList.indexOf(dataset); - idList[index].append(id); + if (! datasetList.contains(dataset)) + { + datasetList << dataset; + QList myList; + myList << id; + idList.append(myList); + } + else + { + index = datasetList.indexOf(dataset); + idList[index].append(id); + } } } } @@ -1566,20 +1570,27 @@ bool PragaProject::downloadDailyDataArkimet(QList variables, bool prec0 QDate date1 = startDate; QDate date2 = std::min(date1.addDays(MAXDAYS_DOWNLOAD_DAILY), endDate); - while (date1 <= endDate) + bool isOk = true; + while (date1 <= endDate && isOk) { - myDownload->downloadDailyData(date1, date2, datasetList[i], idList[i], arkIdVar, prec0024); - if (showInfo) { updateProgressBar(startDate.daysTo(date2) + 1); } + isOk = myDownload->downloadDailyData(date1, date2, datasetList[i], idList[i], arkIdVar, prec0024, errorString); + if (! isOk) + { + logError(); + errorString = ""; + } + date1 = date2.addDays(1); date2 = std::min(date1.addDays(MAXDAYS_DOWNLOAD_DAILY), endDate); } - if (showInfo) closeProgressBar(); + if (showInfo) + closeProgressBar(); } delete myDownload; @@ -1612,22 +1623,26 @@ bool PragaProject::downloadHourlyDataArkimet(QList variables, QDate sta bool isSelection = isSelectionPointsActive(meteoPoints, nrMeteoPoints); for( int i=0; i < nrMeteoPoints; i++ ) { - if (!isSelection || meteoPoints[i].selected) + if (! isSelection || meteoPoints[i].selected) { id = QString::fromStdString(meteoPoints[i].id); dataset = QString::fromStdString(meteoPoints[i].dataset); - if (!datasetList.contains(dataset)) + // if the point doesn't have dataset, it is not downloaded from arkimet + if (! dataset.isEmpty()) { - datasetList << dataset; - QList myList; - myList << id; - idList.append(myList); - } - else - { - index = datasetList.indexOf(dataset); - idList[index].append(id); + if (! datasetList.contains(dataset)) + { + datasetList << dataset; + QList myList; + myList << id; + idList.append(myList); + } + else + { + index = datasetList.indexOf(dataset); + idList[index].append(id); + } } } } @@ -1643,15 +1658,20 @@ bool PragaProject::downloadHourlyDataArkimet(QList variables, QDate sta { setProgressBar("Download hourly data from: " + startDate.toString("yyyy-MM-dd") + " to:" + endDate.toString("yyyy-MM-dd") + " dataset:" + datasetList[i], nrDays); } - while (date1 <= endDate) + bool isOk = true; + while (date1 <= endDate && isOk) { if (showInfo) { updateProgressBar(startDate.daysTo(date2) + 1); } - if (! myDownload->downloadHourlyData(date1, date2, datasetList[i], idList[i], arkIdVar)) - updateProgressBarText("NO DATA"); + isOk = myDownload->downloadHourlyData(date1, date2, datasetList[i], idList[i], arkIdVar, errorString); + if (! isOk) + { + updateProgressBarText(errorString); + errorString = ""; + } date1 = date2.addDays(1); date2 = std::min(date1.addDays(MAXDAYS_DOWNLOAD_HOURLY), endDate); @@ -1662,7 +1682,6 @@ bool PragaProject::downloadHourlyDataArkimet(QList variables, QDate sta } } - delete myDownload; return true; } @@ -1670,13 +1689,11 @@ bool PragaProject::downloadHourlyDataArkimet(QList variables, QDate sta bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoComputation elab1MeteoComp, QString aggregationString, float threshold, gis::Crit3DRasterGrid* zoneGrid, QDate startDate, QDate endDate, QString periodType, std::vector &outputValues, bool showInfo) { - aggregationMethod spatialElab = getAggregationMethod(aggregationString.toStdString()); std::vector > meteoGridRow(zoneGrid->header->nrRows, std::vector(zoneGrid->header->nrCols, NODATA)); std::vector > meteoGridCol(zoneGrid->header->nrRows, std::vector(zoneGrid->header->nrCols, NODATA)); meteoGridDbHandler->meteoGrid()->saveRowColfromZone(zoneGrid, meteoGridRow, meteoGridCol); - float percValue; bool isMeteoGrid = true; std::string id; @@ -1705,8 +1722,8 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo for (int zoneCol = 0; zoneCol < zoneGrid->header->nrCols; zoneCol++) { float zoneValue = zoneGrid->value[zoneRow][zoneCol]; - double utmx = zoneGrid->utmPoint(zoneRow,zoneCol)->x; - double utmy = zoneGrid->utmPoint(zoneRow,zoneCol)->y; + double utmx = zoneGrid->utmPoint(zoneRow, zoneCol)->x; + double utmy = zoneGrid->utmPoint(zoneRow, zoneCol)->y; if (! isEqual(zoneValue, zoneGrid->header->flag)) { @@ -1724,13 +1741,21 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo for (unsigned int zonePos = 0; zonePos < zoneVector.size(); zonePos++) { - double lat; - double lon; - utmXvector[zonePos] = utmXvector[zonePos] / count[zonePos]; - utmYvector[zonePos] = utmYvector[zonePos] / count[zonePos]; - gis::getLatLonFromUtm(gisSettings, utmXvector[zonePos], utmYvector[zonePos], &lat, &lon); - latVector.push_back(lat); - lonVector.push_back(lon); + // average x, y + utmXvector[zonePos] = utmXvector[zonePos] / count[zonePos]; + utmYvector[zonePos] = utmYvector[zonePos] / count[zonePos]; + double lat, lon; + gis::getLatLonFromUtm(gisSettings, utmXvector[zonePos], utmYvector[zonePos], &lat, &lon); + latVector.push_back(lat); + lonVector.push_back(lon); + } + + // save point properties + int nrAggregationPoints = int(zoneVector.size()); + if (! aggregationDbHandler->writeAggregationPointProperties(nrAggregationPoints, aggregationString, lonVector, latVector)) + { + errorString = aggregationDbHandler->error(); + return false; } int infoStep = 0; @@ -1748,10 +1773,8 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo for (int col = 0; col < meteoGridDbHandler->gridStructure().header().nrCols; col++) { - if (meteoGridDbHandler->meteoGrid()->getMeteoPointActiveId(row, col, &id)) { - Crit3DMeteoPoint* meteoPoint = meteoGridDbHandler->meteoGrid()->meteoPointPointer(row, col); // copy data to MPTemp @@ -1786,7 +1809,6 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo { for (int zoneCol = 0; zoneCol < zoneGrid->header->nrCols; zoneCol++) { - float zoneValue = zoneGrid->value[zoneRow][zoneCol]; if (! isEqual(zoneValue, zoneGrid->header->flag)) { @@ -1794,6 +1816,7 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo if (zoneIndex < 1 || zoneIndex > zoneGrid->maximum) { errorString = "invalid zone index: " + QString::number(zoneIndex); + errorString += "\nZone number has to be between 1 and " + QString::number(zoneGrid->maximum); return false; } @@ -1828,12 +1851,11 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo { case aggrAverage: { - res = statistics::mean(validValues, size); + res = statistics::mean(validValues); break; } case aggrMedian: { - res = sorting::percentile(validValues, size, 50.0, true); break; } @@ -1850,7 +1872,7 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo default: { // default: average - res = statistics::mean(validValues, size); + res = statistics::mean(validValues); break; } } @@ -1862,12 +1884,12 @@ bool PragaProject::averageSeriesOnZonesMeteoGrid(meteoVariable variable, meteoCo { zoneVector[zonePos].clear(); } - } // save dailyElabAggregation result into DB if (showInfo) setProgressBar("Save data...", 0); - if (! aggregationDbHandler->saveAggrData(int(zoneGrid->maximum), aggregationString, periodType, startDate, endDate, variable, dailyElabAggregation, lonVector, latVector)) + if (! aggregationDbHandler->saveAggrData(int(zoneGrid->maximum), aggregationString, periodType, + startDate, endDate, variable, dailyElabAggregation)) { errorString = aggregationDbHandler->error(); if (showInfo) closeProgressBar(); @@ -3452,14 +3474,16 @@ bool PragaProject::loadXMLImportData(QString fileName) } errorString = ""; - if (!inOutData->importDataMain(fileName, errorString)) + if (! inOutData->importDataMain(fileName, errorString)) { + logError(); return false; } return true; } + bool PragaProject::loadXMLExportData(QString code, QDateTime myFirstTime, QDateTime myLastTime) { errorString = ""; @@ -3486,23 +3510,27 @@ bool PragaProject::loadXMLExportData(QString code, QDateTime myFirstTime, QDateT fixedString.insert(0, " "); } } + int variableCodeFirstChar = inOutData->getVariableCodeFirstChar(); int whiteSpaces = variableCodeFirstChar - (fixedString.length()+1); - for (int i = 0; igetVariableCodeAttribute(); - if (!attribute.isEmpty()) + if (! attribute.isEmpty()) { fixedString = fixedString + attribute; } + int timeFirstChar = inOutData->getTimeFirstChar(); whiteSpaces = timeFirstChar - (fixedString.length()+1); - for (int i = 0; igetVariableAlign(); int variableFirstChar = inOutData->getVariableFirstChar(); int variableNrChar = inOutData->getVariableNrChar(); @@ -3653,6 +3681,7 @@ bool PragaProject::loadXMLExportDataGrid(QString code, QDateTime myFirstTime, QD errorString = "Invalid filename" ; return false; } + QString variable = inOutData->getVariableExport(); meteoVariable meteoVar = getMeteoVar(variable.toStdString()); if (meteoVar == noMeteoVar) @@ -3660,39 +3689,45 @@ bool PragaProject::loadXMLExportDataGrid(QString code, QDateTime myFirstTime, QD errorString = "Unknown meteo variable: " + variable; return false; } + QString fixedString = ""; int pointCodeFirstChar = inOutData->getPointCodeFirstChar(); if (pointCodeFirstChar != NODATA) { fixedString = code; - for (int i = 0; igetVariableCodeFirstChar(); int whiteSpaces = variableCodeFirstChar - (fixedString.length()+1); - for (int i = 0; igetVariableCodeAttribute(); - if (!attribute.isEmpty()) + if (! attribute.isEmpty()) { fixedString = fixedString + attribute; } + int timeFirstChar = inOutData->getTimeFirstChar(); whiteSpaces = timeFirstChar - (fixedString.length()+1); - for (int i = 0; igetVariableAlign(); int variableFirstChar = inOutData->getVariableFirstChar(); int variableNrChar = inOutData->getVariableNrChar(); QString variableFormat = inOutData->getVariableFormat(); QChar charFormat = variableFormat[variableFormat.length()-1]; int nDecimals = variableFormat.mid(variableFormat.length()-2,1).toInt(); + if (variableAlign.isEmpty()) { variableAlign = "right"; //default @@ -3702,6 +3737,7 @@ bool PragaProject::loadXMLExportDataGrid(QString code, QDateTime myFirstTime, QD errorString = "Invalid alignment: " + variableAlign; return false; } + QString flagAccepted = inOutData->getVariableFlagAccepted(); int flagFirstChar = 0; if (!flagAccepted.isEmpty()) diff --git a/agrolib/pragaProject/saveClimaLayout.cpp b/agrolib/pragaProject/saveClimaLayout.cpp index 536c1595..b8c49b24 100644 --- a/agrolib/pragaProject/saveClimaLayout.cpp +++ b/agrolib/pragaProject/saveClimaLayout.cpp @@ -45,7 +45,8 @@ void SaveClimaLayout::addElab() QString elabAdded = firstYear + "-" + lastYear + "_" + variable.remove("_") + "_" + period; if (period == "Generic") { - elabAdded = elabAdded + "_" + genericPeriodStartDay + "of" + genericPeriodStartMonth + "-" + genericPeriodEndDay + "of" + genericPeriodEndMonth; + elabAdded = elabAdded + "_" + genericPeriodStartDay + "of" + genericPeriodStartMonth + + "-" + genericPeriodEndDay + "of" + genericPeriodEndMonth; if (genericNYear != "0") { elabAdded = elabAdded + "-+" + genericNYear + "y"; @@ -152,9 +153,9 @@ QList SaveClimaLayout::getList() const return list; } -void SaveClimaLayout::setList(const QList &value) +void SaveClimaLayout::setList(const QList &valueList) { - list = value; + list = valueList; listView.addItems(list); } @@ -163,9 +164,9 @@ QString SaveClimaLayout::getElab1ParamFromdB() const return elab1ParamFromdB; } -void SaveClimaLayout::setElab1ParamFromdB(const QString &value) +void SaveClimaLayout::setElab1ParamFromdB(const QString &valueStr) { - elab1ParamFromdB = value; + elab1ParamFromdB = valueStr; } QString SaveClimaLayout::getFirstYear() const @@ -173,9 +174,9 @@ QString SaveClimaLayout::getFirstYear() const return firstYear; } -void SaveClimaLayout::setFirstYear(const QString &value) +void SaveClimaLayout::setFirstYear(const QString &valueStr) { - firstYear = value; + firstYear = valueStr; } QString SaveClimaLayout::getLastYear() const @@ -183,9 +184,9 @@ QString SaveClimaLayout::getLastYear() const return lastYear; } -void SaveClimaLayout::setLastYear(const QString &value) +void SaveClimaLayout::setLastYear(const QString &valueStr) { - lastYear = value; + lastYear = valueStr; } QString SaveClimaLayout::getVariable() const @@ -193,9 +194,9 @@ QString SaveClimaLayout::getVariable() const return variable; } -void SaveClimaLayout::setVariable(const QString &value) +void SaveClimaLayout::setVariable(const QString &valueStr) { - variable = value; + variable = valueStr; } QString SaveClimaLayout::getPeriod() const @@ -203,9 +204,9 @@ QString SaveClimaLayout::getPeriod() const return period; } -void SaveClimaLayout::setPeriod(const QString &value) +void SaveClimaLayout::setPeriod(const QString &valueStr) { - period = value; + period = valueStr; } QString SaveClimaLayout::getGenericPeriodStartDay() const @@ -223,9 +224,9 @@ QString SaveClimaLayout::getGenericPeriodStartMonth() const return genericPeriodStartMonth; } -void SaveClimaLayout::setGenericPeriodStartMonth(const QString &value) +void SaveClimaLayout::setGenericPeriodStartMonth(const QString &valueStr) { - genericPeriodStartMonth = value; + genericPeriodStartMonth = valueStr; } QString SaveClimaLayout::getGenericPeriodEndDay() const @@ -233,9 +234,9 @@ QString SaveClimaLayout::getGenericPeriodEndDay() const return genericPeriodEndDay; } -void SaveClimaLayout::setGenericPeriodEndDay(const QString &value) +void SaveClimaLayout::setGenericPeriodEndDay(const QString &valueStr) { - genericPeriodEndDay = value; + genericPeriodEndDay = valueStr; } QString SaveClimaLayout::getGenericPeriodEndMonth() const @@ -243,9 +244,9 @@ QString SaveClimaLayout::getGenericPeriodEndMonth() const return genericPeriodEndMonth; } -void SaveClimaLayout::setGenericPeriodEndMonth(const QString &value) +void SaveClimaLayout::setGenericPeriodEndMonth(const QString &valueStr) { - genericPeriodEndMonth = value; + genericPeriodEndMonth = valueStr; } QString SaveClimaLayout::getGenericNYear() const @@ -253,9 +254,9 @@ QString SaveClimaLayout::getGenericNYear() const return genericNYear; } -void SaveClimaLayout::setGenericNYear(const QString &value) +void SaveClimaLayout::setGenericNYear(const QString &valueStr) { - genericNYear = value; + genericNYear = valueStr; } QString SaveClimaLayout::getSecondElab() const @@ -263,9 +264,9 @@ QString SaveClimaLayout::getSecondElab() const return secondElab; } -void SaveClimaLayout::setSecondElab(const QString &value) +void SaveClimaLayout::setSecondElab(const QString &valueStr) { - secondElab = value; + secondElab = valueStr; } QString SaveClimaLayout::getElab2Param() const @@ -273,9 +274,9 @@ QString SaveClimaLayout::getElab2Param() const return elab2Param; } -void SaveClimaLayout::setElab2Param(const QString &value) +void SaveClimaLayout::setElab2Param(const QString &valueStr) { - elab2Param = value; + elab2Param = valueStr; } QString SaveClimaLayout::getElab() const @@ -283,9 +284,9 @@ QString SaveClimaLayout::getElab() const return elab; } -void SaveClimaLayout::setElab(const QString &value) +void SaveClimaLayout::setElab(const QString &valueStr) { - elab = value; + elab = valueStr; } QString SaveClimaLayout::getElab1Param() const @@ -293,7 +294,7 @@ QString SaveClimaLayout::getElab1Param() const return elab1Param; } -void SaveClimaLayout::setElab1Param(const QString &value) +void SaveClimaLayout::setElab1Param(const QString &valueStr) { - elab1Param = value; + elab1Param = valueStr; } diff --git a/agrolib/pragaProject/saveClimaLayout.h b/agrolib/pragaProject/saveClimaLayout.h index e76ee492..22098c25 100644 --- a/agrolib/pragaProject/saveClimaLayout.h +++ b/agrolib/pragaProject/saveClimaLayout.h @@ -16,33 +16,33 @@ class SaveClimaLayout : public QDialog SaveClimaLayout(); QString getFirstYear() const; - void setFirstYear(const QString &value); + void setFirstYear(const QString &valueStr); QString getLastYear() const; - void setLastYear(const QString &value); + void setLastYear(const QString &valueStr); QString getVariable() const; - void setVariable(const QString &value); + void setVariable(const QString &valueStr); QString getPeriod() const; - void setPeriod(const QString &value); + void setPeriod(const QString &valueStr); QString getGenericPeriodEnd() const; - void setGenericPeriodEnd(const QString &value); + void setGenericPeriodEnd(const QString &valueStr); QString getGenericNYear() const; - void setGenericNYear(const QString &value); + void setGenericNYear(const QString &valueStr); QString getSecondElab() const; - void setSecondElab(const QString &value); + void setSecondElab(const QString &valueStr); QString getElab2Param() const; - void setElab2Param(const QString &value); + void setElab2Param(const QString &valueStr); QString getElab() const; - void setElab(const QString &value); + void setElab(const QString &valueStr); QString getElab1Param() const; - void setElab1Param(const QString &value); + void setElab1Param(const QString &valueStr); QString getGenericPeriodStartDay() const; void setGenericPeriodStartDay(const QString &value); QString getGenericPeriodStartMonth() const; - void setGenericPeriodStartMonth(const QString &value); + void setGenericPeriodStartMonth(const QString &valueStr); QString getGenericPeriodEndDay() const; - void setGenericPeriodEndDay(const QString &value); + void setGenericPeriodEndDay(const QString &valueStr); QString getGenericPeriodEndMonth() const; - void setGenericPeriodEndMonth(const QString &value); + void setGenericPeriodEndMonth(const QString &valueStr); void addElab(); void deleteRaw(); @@ -52,10 +52,10 @@ class SaveClimaLayout : public QDialog void loadElabList(); QList getList() const; - void setList(const QList &value); + void setList(const QList &valueList); QString getElab1ParamFromdB() const; - void setElab1ParamFromdB(const QString &value); + void setElab1ParamFromdB(const QString &valueStr); private: diff --git a/agrolib/project/dialogInterpolation.cpp b/agrolib/project/dialogInterpolation.cpp index 730dc72b..b78bd227 100644 --- a/agrolib/project/dialogInterpolation.cpp +++ b/agrolib/project/dialogInterpolation.cpp @@ -136,13 +136,13 @@ DialogInterpolation::DialogInterpolation(Project *myProject) layoutDetrending->addWidget(localDetrendingEdit); - QLabel *labelElFunction = new QLabel(tr("Fitting function for elevation:")); + QLabel *labelElFunction = new QLabel(tr("fitting function for elevation")); layoutDetrending->addWidget(labelElFunction); std::map::const_iterator itElFunc; for (itElFunc = fittingFunctionNames.begin(); itElFunc != fittingFunctionNames.end(); ++itElFunc) { - if (itElFunc->first == "linear" || itElFunc->first == "Triple piecewise" || itElFunc->first == "Nonlinear Frei function (5 parameters)" || itElFunc->first == "Nonlinear Frei function (6 parameters)") + if (itElFunc->first == "linear") continue; elevationFunctionEdit.addItem(QString::fromStdString(itElFunc->first), QString::fromStdString(itElFunc->first)); } @@ -286,7 +286,7 @@ void DialogInterpolation::accept() } for (int i = 0; i < proxyListCheck->count(); i++) - _interpolationSettings->setValueSelectedCombination(unsigned(i), proxyListCheck->item(i)->checkState()); + _interpolationSettings->setActiveSelectedCombination(unsigned(i), proxyListCheck->item(i)->checkState()); QString algorithmString = algorithmEdit.itemData(algorithmEdit.currentIndex()).toString(); _interpolationSettings->setInterpolationMethod(interpolationMethodNames.at(algorithmString.toStdString())); diff --git a/agrolib/project/interpolationCmd.cpp b/agrolib/project/interpolationCmd.cpp index e32c1c89..97620915 100644 --- a/agrolib/project/interpolationCmd.cpp +++ b/agrolib/project/interpolationCmd.cpp @@ -264,7 +264,10 @@ bool interpolationRaster(std::vector &myPoints, C return false; } - raster.initializeParameters(*raster.header); + if (mySettings->getUseLocalDetrending()) + { + raster.initializeParameters(*raster.header); + } float myX, myY; std::vector proxyValues; @@ -277,7 +280,7 @@ bool interpolationRaster(std::vector &myPoints, C gis::getUtmXYFromRowColSinglePrecision(*outputGrid, myRow, myCol, &myX, &myY); float myZ = raster.value[myRow][myCol]; if (mySettings->getUseLocalDetrending()) - mySettings->setFittingParameters(raster.prepareParameters(myRow, myCol)); + mySettings->setFittingParameters(raster.prepareParameters(myRow, myCol, mySettings->getSelectedCombination().getActiveList())); if (! isEqual(myZ, outputGrid->header->flag)) { if (getUseDetrendingVar(myVar)) diff --git a/agrolib/project/meteoMaps.cpp b/agrolib/project/meteoMaps.cpp index f790088a..e20d9863 100644 --- a/agrolib/project/meteoMaps.cpp +++ b/agrolib/project/meteoMaps.cpp @@ -2,6 +2,7 @@ #include "basicMath.h" #include "meteo.h" #include "meteoMaps.h" +#include "gis.h" Crit3DDailyMeteoMaps::Crit3DDailyMeteoMaps(const gis::Crit3DRasterGrid& DEM) diff --git a/agrolib/project/project.cpp b/agrolib/project/project.cpp index 8064874e..2df0a0a0 100644 --- a/agrolib/project/project.cpp +++ b/agrolib/project/project.cpp @@ -17,6 +17,7 @@ #include "importData.h" #include "dialogSummary.h" #include "waterTableWidget.h" +#include "utilities.h" #include @@ -197,9 +198,10 @@ void Project::setProxyDEM() } -bool Project::checkProxy(const Crit3DProxy &myProxy, QString* error) +bool Project::checkProxy(Crit3DProxy &myProxy, QString* error) { std::string name_ = myProxy.getName(); + QList myList; if (name_ == "") { @@ -215,6 +217,79 @@ bool Project::checkProxy(const Crit3DProxy &myProxy, QString* error) return false; } + if (isHeight) + { + if (parameters->contains("fitting_function")) + { + std::string elevationFuction = parameters->value("fitting_function").toString().toStdString(); + if (fittingFunctionNames.find(elevationFuction) == fittingFunctionNames.end()) + { + errorString = "Unknown function for elevation. Remove the field from the .ini file or choose between: piecewise_two, triple_piecewise, free_triple_piecewise."; + return false; + } + else + myProxy.setFittingFunctionName(fittingFunctionNames.at(elevationFuction)); + + if (parameters->contains("fitting_parameters")) + { + unsigned int nrParameters = NODATA; + + if (myProxy.getFittingFunctionName() == piecewiseTwo) + nrParameters = 4; + else if (myProxy.getFittingFunctionName() == piecewiseThree) + nrParameters = 5; + else if (myProxy.getFittingFunctionName()== piecewiseThreeFree) + nrParameters = 6; + + myList = parameters->value("fitting_parameters").toStringList(); + if (myList.size() != nrParameters*2) + { + *error = "Wrong number of fitting parameters for proxy: " + QString::fromStdString(name_); + return false; + } + + myProxy.setFittingParametersRange(StringListToDouble(myList)); + } + } + else + { + if (parameters->contains("fitting_parameters")) + { + myList = parameters->value("fitting_parameters").toStringList(); + + if (myList.size() == 8) + myProxy.setFittingFunctionName(piecewiseTwo); + else if (myList.size() == 10) + myProxy.setFittingFunctionName(piecewiseThree); + else if (myList.size() == 12) + myProxy.setFittingFunctionName(piecewiseThreeFree); + else + { + *error = "Wrong number of fitting parameters for proxy: " + QString::fromStdString(name_); + return false; + } + myProxy.setFittingParametersRange(StringListToDouble(myList)); + } + } + } + else + { + myProxy.setFittingFunctionName(linear); + if(parameters->contains("fitting_parameters")) + { + unsigned int nrParameters = 2; + + myList = parameters->value("fitting_parameters").toStringList(); + if (myList.size() != nrParameters*2) + { + *error = "Wrong number of fitting parameters for proxy: " + QString::fromStdString(name_); + return false; + } + + myProxy.setFittingParametersRange(StringListToDouble(myList)); + } + } + return true; } @@ -687,25 +762,6 @@ bool Project::loadParameters(QString parametersFileName) if (parameters->contains("stddev_threshold")) myProxy->setStdDevThreshold(parameters->value("stddev_threshold").toFloat()); - if (parameters->contains("fitting_parameters")) - { - unsigned int nrParameters; - - if (getProxyPragaName(name_.toStdString()) == proxyHeight) - nrParameters = 5; - else - nrParameters = 1; - - myList = parameters->value("fitting_parameters").toStringList(); - if (myList.size() != nrParameters*2 && myList.size() != (nrParameters-1)*2 && myList.size() != (nrParameters+1)*2) //TODO: change - { - errorString = "Wrong number of fitting parameters for proxy: " + name_; - return false; - } - - myProxy->setFittingParametersRange(StringListToDouble(myList)); - } - if (! parameters->contains("active")) { errorString = "active not specified for proxy " + QString::fromStdString(myProxy->getName()); @@ -860,8 +916,13 @@ Crit3DTime Project::getCrit3DCurrentTime() QDateTime Project::getCurrentTime() { QDateTime myDateTime; - myDateTime.setDate(this->currentDate); - return myDateTime.addSecs(this->currentHour * HOUR_SECONDS); + if (gisSettings.isUTC) + { + myDateTime.setTimeSpec(Qt::UTC); + } + + myDateTime.setDate(currentDate); + return myDateTime.addSecs(currentHour * HOUR_SECONDS); } @@ -1028,7 +1089,8 @@ bool Project::loadDEM(QString myFileName) setProxyDEM(); interpolationSettings.setProxyLoaded(false); - if (! updateProxy()) return false; + if (! updateProxy()) + return false; //set interpolation settings DEM interpolationSettings.setCurrentDEM(&DEM); @@ -1048,8 +1110,6 @@ bool Project::loadMeteoPointsDB(QString fileName) closeMeteoPointsDB(); - logInfoGUI("Load meteo points DB = " + fileName); - dbPointsFileName = fileName; QString dbName = getCompleteFileName(fileName, PATH_METEOPOINT); if (! QFile(dbName).exists()) @@ -1061,7 +1121,7 @@ bool Project::loadMeteoPointsDB(QString fileName) meteoPointsDbHandler = new Crit3DMeteoPointsDbHandler(dbName); if (! meteoPointsDbHandler->getErrorString().isEmpty()) { - errorString = "Function loadMeteoPointsDB:\n" + dbName + "\n" + meteoPointsDbHandler->getErrorString(); + errorString = meteoPointsDbHandler->getErrorString(); closeMeteoPointsDB(); return false; } @@ -1077,7 +1137,7 @@ bool Project::loadMeteoPointsDB(QString fileName) errorString = ""; if (! meteoPointsDbHandler->getPropertiesFromDb(listMeteoPoints, gisSettings, errorString)) { - errorString = "Error in reading table 'point_properties'\n" + errorString; + errorString = "Error in reading the table point_properties\n" + errorString; closeMeteoPointsDB(); return false; } @@ -1085,7 +1145,7 @@ bool Project::loadMeteoPointsDB(QString fileName) nrMeteoPoints = listMeteoPoints.size(); if (nrMeteoPoints == 0) { - errorString = "Missing data in the table 'point_properties'\n" + errorString; + errorString = "Missing data in the table point_properties\n" + errorString; closeMeteoPointsDB(); return false; } @@ -1128,6 +1188,7 @@ bool Project::loadMeteoPointsDB(QString fileName) { logError("Error reading proxy values"); } + closeLogInfo(); // position with respect to DEM if (DEM.isLoaded) @@ -1137,7 +1198,6 @@ bool Project::loadMeteoPointsDB(QString fileName) meteoPointsLoaded = true; logInfo("Meteo points DB = " + dbName); - closeLogInfo(); return true; } @@ -1669,6 +1729,7 @@ bool Project::loadMeteoGridMonthlyData(QDate firstDate, QDate lastDate, bool sho return true; } + QDateTime Project::findDbPointLastTime() { QDateTime lastTime; @@ -1677,7 +1738,10 @@ QDateTime Project::findDbPointLastTime() QDateTime lastDateD; lastDateD.setTimeSpec(Qt::UTC); lastDateD = meteoPointsDbHandler->getLastDate(daily); - if (! lastDateD.isNull()) lastTime = lastDateD; + if (! lastDateD.isNull()) + { + lastTime = lastDateD; + } QDateTime lastDateH; lastDateH.setTimeSpec(Qt::UTC); @@ -1685,15 +1749,20 @@ QDateTime Project::findDbPointLastTime() if (! lastDateH.isNull()) { - if (! lastTime.isNull()) + if (! lastDateD.isNull()) + { lastTime = (lastDateD > lastDateH) ? lastDateD : lastDateH; + } else + { lastTime = lastDateH; + } } return lastTime; } + QDateTime Project::findDbPointFirstTime() { QDateTime firstTime; @@ -1819,7 +1888,7 @@ bool Project::loadProxyGrids() } else { - errorString = "Error loading proxy grid " + fileName; + errorString = "Error loading raster proxy:\n" + fileName + "\nHow to fix it: check the proxy section in the parameters.ini"; return false; } @@ -1892,13 +1961,11 @@ bool Project::updateProxy() { if (! interpolationSettings.getProxyLoaded()) { - if (loadProxyGrids()) - { - interpolationSettings.setProxyLoaded(true); - } - else + if (! loadProxyGrids()) return false; + interpolationSettings.setProxyLoaded(true); + if (meteoPointsDbHandler != nullptr) { if (! readProxyValues()) @@ -2140,20 +2207,18 @@ bool Project::interpolationOutputPoints(std::vector initialize(); std::vector obs; std::vector pre; - float value; - for (int i = 0; i < nrMeteoPoints; i++) { if (meteoPoints[i].active) { - value = meteoPoints[i].getMeteoPointValue(myTime, myVar, meteoSettings); + float value = meteoPoints[i].currentValue; if (! isEqual(value, NODATA) && ! isEqual(meteoPoints[i].residual, NODATA)) { @@ -2198,11 +2263,11 @@ bool Project::interpolationCv(meteoVariable myVar, const Crit3DTime& myTime, cro } if (myVar == dailyGlobalRadiation || + myVar == globalIrradiance || myVar == dailyLeafWetness || myVar == dailyWindVectorDirectionPrevailing || myVar == dailyWindVectorIntensityAvg || - myVar == dailyWindVectorIntensityMax || - myVar == globalIrradiance) + myVar == dailyWindVectorIntensityMax ) { logError("Cross validation is not available for " + QString::fromStdString(getVariableString(myVar))); return false; @@ -2212,7 +2277,7 @@ bool Project::interpolationCv(meteoVariable myVar, const Crit3DTime& myTime, cro std::string errorStdStr; // check quality and pass data to interpolation - if (!checkAndPassDataToInterpolation(quality, myVar, meteoPoints, nrMeteoPoints, myTime, + if (! checkAndPassDataToInterpolation(quality, myVar, meteoPoints, nrMeteoPoints, myTime, &qualityInterpolationSettings, &interpolationSettings, meteoSettings, &climateParameters, interpolationPoints, checkSpatialQuality, errorStdStr)) @@ -2231,7 +2296,7 @@ bool Project::interpolationCv(meteoVariable myVar, const Crit3DTime& myTime, cro if (! computeResiduals(myVar, meteoPoints, nrMeteoPoints, interpolationPoints, &interpolationSettings, meteoSettings, true, true)) return false; - if (! computeStatisticsCrossValidation(myTime, myVar, myStats)) + if (! computeStatisticsCrossValidation(myStats)) return false; return true; @@ -2323,7 +2388,7 @@ bool Project::interpolationDemLocalDetrending(meteoVariable myVar, const Crit3DT getProxyValuesXY(x, y, &interpolationSettings, proxyValues); std::vector subsetInterpolationPoints; - localSelection(interpolationPoints, subsetInterpolationPoints, x, y, interpolationSettings); + localSelection(interpolationPoints, subsetInterpolationPoints, x, y,outputPoints[i].z, interpolationSettings); if (! preInterpolation(subsetInterpolationPoints, &interpolationSettings, meteoSettings, &climateParameters, meteoPoints, nrMeteoPoints, myVar, myTime, errorStdStr)) { @@ -2347,7 +2412,7 @@ bool Project::interpolationDemLocalDetrending(meteoVariable myVar, const Crit3DT myRaster->initializeGrid(myHeader); myRaster->initializeParameters(myHeader); - if(!setAllFittingRanges(myCombination, &interpolationSettings)) + if(!setHeightFittingRange(myCombination, &interpolationSettings)) { errorString = "Error in function preInterpolation: \n couldn't set fitting ranges."; return false; @@ -2367,9 +2432,9 @@ bool Project::interpolationDemLocalDetrending(meteoVariable myVar, const Crit3DT if (! getProxyValuesXY(x, y, &interpolationSettings, proxyValues)) interpolationSettings.setProxiesComplete(false); std::vector subsetInterpolationPoints; - localSelection(interpolationPoints, subsetInterpolationPoints, x, y, interpolationSettings); - if (interpolationSettings.getUseLocalDetrending()) - interpolationSettings.setFittingParameters(myRaster->prepareParameters(row, col)); + localSelection(interpolationPoints, subsetInterpolationPoints, x, y, z, interpolationSettings); + if (interpolationSettings.getUseLocalDetrending()) + interpolationSettings.setFittingParameters(myRaster->prepareParameters(row, col, myCombination.getActiveList())); if (! preInterpolation(subsetInterpolationPoints, &interpolationSettings, meteoSettings, &climateParameters, meteoPoints, nrMeteoPoints, myVar, myTime, errorStdStr)) { @@ -2377,11 +2442,11 @@ bool Project::interpolationDemLocalDetrending(meteoVariable myVar, const Crit3DT return false; } - myRaster->value[row][col] = interpolate(subsetInterpolationPoints, &interpolationSettings, meteoSettings, myVar, x, y, z, proxyValues, true); - if (interpolationSettings.getUseLocalDetrending()) - myRaster->setParametersForRowCol(row, col, interpolationSettings.getFittingParameters()); + myRaster->setParametersForRowCol(row, col, interpolationSettings.getFittingParameters()); + interpolationSettings.clearFitting(); + interpolationSettings.setCurrentCombination(interpolationSettings.getSelectedCombination()); } } } @@ -2624,11 +2689,12 @@ bool Project::interpolationGrid(meteoVariable myVar, const Crit3DTime& myTime) std::vector proxyValues; proxyValues.resize(unsigned(interpolationSettings.getProxyNr())); - if(!setAllFittingRanges(myCombination, &interpolationSettings)) - { - errorString = "Error in function preInterpolation: \n couldn't set fitting ranges."; - return false; - } + if (interpolationSettings.getUseLocalDetrending()) + if(!setHeightFittingRange(myCombination, &interpolationSettings)) + { + errorString = "Error in function preInterpolation: \n couldn't set fitting ranges."; + return false; + } float interpolatedValue = NODATA; unsigned int i, proxyIndex; @@ -2666,12 +2732,11 @@ bool Project::interpolationGrid(meteoVariable myVar, const Crit3DTime& myTime) proxyIndex++; } } - if (interpolationSettings.getUseLocalDetrending()) { std::vector subsetInterpolationPoints; - localSelection(interpolationPoints, subsetInterpolationPoints, myX, myY, interpolationSettings); - interpolationSettings.setFittingParameters(meteoGridDbHandler->meteoGrid()->dataMeteoGrid.prepareParameters(row, col)); + localSelection(interpolationPoints, subsetInterpolationPoints, myX, myY, myZ, interpolationSettings); + interpolationSettings.setFittingParameters(meteoGridDbHandler->meteoGrid()->dataMeteoGrid.prepareParameters(row, col, myCombination.getActiveList())); if (! preInterpolation(subsetInterpolationPoints, &interpolationSettings, meteoSettings, &climateParameters, meteoPoints, nrMeteoPoints, myVar, myTime, errorStdStr)) { @@ -2720,7 +2785,9 @@ float Project::meteoDataConsistency(meteoVariable myVar, const Crit3DTime& timeI { float dataConsistency = 0.0; for (int i = 0; i < nrMeteoPoints; i++) + { dataConsistency = MAXVALUE(dataConsistency, meteoPoints[i].obsDataConsistencyH(myVar, timeIni, timeFin)); + } return dataConsistency; } @@ -2883,6 +2950,7 @@ frequencyType Project::getCurrentFrequency() const return currentFrequency; } + void Project::setCurrentFrequency(const frequencyType &value) { currentFrequency = value; @@ -2996,6 +3064,7 @@ void Project::saveProxies() if (myProxy->getGridName() != "") parameters->setValue("raster", getRelativePath(QString::fromStdString(myProxy->getGridName()))); if (myProxy->getStdDevThreshold() != NODATA) parameters->setValue("stddev_threshold", QString::number(myProxy->getStdDevThreshold())); if (myProxy->getFittingParametersRange().size() > 0) parameters->setValue("fitting_parameters", DoubleVectorToStringList(myProxy->getFittingParametersRange())); + if (getProxyPragaName(myProxy->getName()) == proxyHeight && myProxy->getFittingFunctionName() != noFunction) parameters->setValue("fitting_function", QString::fromStdString(getKeyStringElevationFunction(myProxy->getFittingFunctionName()))); parameters->endGroup(); } } @@ -3139,7 +3208,6 @@ bool Project::loadProject() { errorType = ERROR_SETTINGS; errorString = "Load parameters failed.\n" + errorString; - logError(); return false; } @@ -3149,7 +3217,7 @@ bool Project::loadProject() if (dbPointsFileName != "") if (! loadMeteoPointsDB(dbPointsFileName)) { - errorString = "load Meteo Points DB failed"; + errorString = "load Meteo Points DB failed:\n" + dbPointsFileName; errorType = ERROR_DBPOINT; logError(); return false; @@ -3281,7 +3349,7 @@ void Project::showMeteoWidgetPoint(std::string idMeteoPoint, std::string namePoi QDateTime lastHourly = meteoPointsDbHandler->getLastDate(hourly, idMeteoPoint); bool hasHourlyData = !(firstHourly.isNull() || lastHourly.isNull()); - if (!hasDailyData && !hasHourlyData) + if (! hasDailyData && ! hasHourlyData) { logInfoGUI("No data."); return; @@ -3344,11 +3412,15 @@ void Project::showMeteoWidgetPoint(std::string idMeteoPoint, std::string namePoi if (hasDailyData) { - meteoWidgetPoint->setDateIntervalDaily(firstDaily, lastDaily); + meteoWidgetPoint->setDailyRange(firstDaily, lastDaily); } if (hasHourlyData) { - meteoWidgetPoint->setDateIntervalHourly(firstHourly.date(), lastHourly.date()); + meteoWidgetPoint->setHourlyRange(firstHourly.date(), lastHourly.date()); + if (! hasDailyData) + { + meteoWidgetPoint->setFrequency(hourly); + } } meteoWidgetPoint->setCurrentDate(this->currentDate); @@ -3366,7 +3438,6 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) QDate firstMonthlyDate = meteoGridDbHandler->getFirstMonthlytDate(); QDate lastMonthlyDate = meteoGridDbHandler->getLastMonthlyDate(); - QDateTime firstDateTime, lastDateTime; if (meteoGridDbHandler->getFirstHourlyDate().isValid()) { @@ -3378,21 +3449,24 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) } int meteoWidgetId = 0; - if (meteoWidgetGridList.isEmpty() || meteoGridDbHandler->gridStructure().isEnsemble()) + if (meteoWidgetGridList.isEmpty()) { isAppend = false; } if (meteoGridDbHandler->gridStructure().isEnsemble()) { - isAppend = false; - logInfoGUI("Meteo grid is ensemble: append mode is not possible, a new widget is opening."); + if (isAppend) + { + isAppend = false; + logWarning("Meteo grid is ensemble: append mode is not possible.\nA new meteo widget will be open."); + } } + logInfoGUI("Loading data...\n"); + if (isAppend) { - logInfoGUI("Loading data...\n"); - if (! meteoGridDbHandler->gridStructure().isFixedFields()) { if (meteoGridDbHandler->isDaily()) @@ -3401,6 +3475,7 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) } if (meteoGridDbHandler->isHourly()) { + logInfoGUI("Loading hourly data...\n"); meteoGridDbHandler->loadGridHourlyData(errorString, QString::fromStdString(idCell), firstDateTime, lastDateTime); } if (meteoGridDbHandler->isMonthly()) @@ -3416,6 +3491,7 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) } if (meteoGridDbHandler->isHourly()) { + logInfoGUI("Loading hourly data...\n"); meteoGridDbHandler->loadGridHourlyDataFixedFields(errorString, QString::fromStdString(idCell), firstDateTime, lastDateTime); } if (meteoGridDbHandler->isMonthly()) @@ -3443,7 +3519,7 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) { bool isGrid = true; Crit3DMeteoWidget* meteoWidgetGrid = new Crit3DMeteoWidget(isGrid, projectPath, meteoSettings); - if (!meteoWidgetGridList.isEmpty()) + if (! meteoWidgetGridList.isEmpty()) { meteoWidgetId = meteoWidgetGridList[meteoWidgetGridList.size()-1]->getMeteoWidgetID()+1; } @@ -3458,8 +3534,6 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) QObject::connect(meteoWidgetGrid, SIGNAL(closeWidgetGrid(int)), this, SLOT(deleteMeteoWidgetGrid(int))); - logInfoGUI("Loading data..."); - if (meteoGridDbHandler->gridStructure().isEnsemble()) { meteoWidgetGrid->setIsEnsemble(true); @@ -3471,11 +3545,11 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) { if (meteoGridDbHandler->isDaily()) { - meteoWidgetGrid->setDateIntervalDaily(firstDate, lastDate); + meteoWidgetGrid->setDailyRange(firstDate, lastDate); } if (meteoGridDbHandler->isHourly()) { - meteoWidgetGrid->setDateIntervalHourly(firstDateTime.date(), lastDateTime.date()); + meteoWidgetGrid->setHourlyRange(firstDateTime.date(), lastDateTime.date()); } } else @@ -3494,7 +3568,7 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) } else { - if (!meteoGridDbHandler->gridStructure().isFixedFields()) + if (! meteoGridDbHandler->gridStructure().isFixedFields()) { if (meteoGridDbHandler->isDaily()) { @@ -3502,6 +3576,7 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) } if (meteoGridDbHandler->isHourly()) { + logInfoGUI("Loading hourly data...\n"); meteoGridDbHandler->loadGridHourlyData(errorString, QString::fromStdString(idCell), firstDateTime, lastDateTime); } if (meteoGridDbHandler->isMonthly()) @@ -3517,6 +3592,7 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) } if (meteoGridDbHandler->isHourly()) { + logInfoGUI("Loading hourly data...\n"); meteoGridDbHandler->loadGridHourlyDataFixedFields(errorString, QString::fromStdString(idCell), firstDateTime, lastDateTime); } if (meteoGridDbHandler->isMonthly()) @@ -3531,11 +3607,11 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) { if (meteoGridDbHandler->isDaily()) { - meteoWidgetGrid->setDateIntervalDaily(firstDate, lastDate); + meteoWidgetGrid->setDailyRange(firstDate, lastDate); } if (meteoGridDbHandler->isHourly()) { - meteoWidgetGrid->setDateIntervalHourly(firstDateTime.date(), lastDateTime.date()); + meteoWidgetGrid->setHourlyRange(firstDateTime.date(), lastDateTime.date()); } meteoWidgetGrid->drawMeteoPoint(meteoGridDbHandler->meteoGrid()->meteoPoint(row,col), isAppend); @@ -3548,7 +3624,6 @@ void Project::showMeteoWidgetGrid(std::string idCell, bool isAppend) void Project::deleteMeteoWidgetPoint(int id) { - for (int i = 0; igetMeteoWidgetID() == id) @@ -3618,14 +3693,14 @@ void Project::showLocalProxyGraph(gis::Crit3DGeoPoint myPoint, gis::Crit3DRaster int row, col; std::vector> parameters; - if (myDataRaster->isLoaded && !myDataRaster->parametersCell.empty()) + if (myDataRaster->isLoaded && !myDataRaster->singleCell.empty()) { gis::getRowColFromXY(*(myDataRaster->header), myUtm, &row, &col); parameters = myDataRaster->getParametersFromRowCol(row, col); } - if (this->meteoGridLoaded && !this->meteoGridDbHandler->meteoGrid()->dataMeteoGrid.parametersCell.empty()) + if (this->meteoGridLoaded && !this->meteoGridDbHandler->meteoGrid()->dataMeteoGrid.singleCell.empty()) { - gis::getGridRowColFromXY(meteoGridDbHandler->meteoGrid()->gridStructure().header(), myPoint.longitude, myPoint.latitude, &row, &col); + gis::getGridRowColFromLonLat(meteoGridDbHandler->meteoGrid()->gridStructure().header(), myPoint.longitude, myPoint.latitude, &row, &col); parameters = meteoGridDbHandler->meteoGrid()->dataMeteoGrid.getParametersFromRowCol(row, col); } @@ -4116,11 +4191,16 @@ bool Project::exportMeteoGridToCsv(QString fileName) for (int col = 0; col < meteoGridDbHandler->meteoGrid()->dataMeteoGrid.header->nrCols; col++) { float value = meteoGridDbHandler->meteoGrid()->dataMeteoGrid.value[row][col]; - std::string id = meteoGridDbHandler->meteoGrid()->meteoPoints()[row][col]->id; - std::string name = meteoGridDbHandler->meteoGrid()->meteoPoints()[row][col]->name; if (value != NO_ACTIVE && value != NODATA) { + int newRow = row; + if (! meteoGridDbHandler->meteoGrid()->gridStructure().isUTM()) + newRow = meteoGridDbHandler->meteoGrid()->gridStructure().nrRow() - 1 - row; + + std::string id = meteoGridDbHandler->meteoGrid()->meteoPoints()[newRow][col]->id; + std::string name = meteoGridDbHandler->meteoGrid()->meteoPoints()[newRow][col]->name; + out << QString::fromStdString(id + ',' + name + ',') + QString::number(value) + "\n"; } } @@ -4372,6 +4452,7 @@ void Project::logInfoGUI(QString myStr) formLog = new FormInfo(); } formLog->showInfo(myStr); + qApp->processEvents(); } else { @@ -4396,6 +4477,31 @@ void Project::logError(QString myStr) } +void Project::logWarning(QString myStr) +{ + errorString = myStr; + logWarning(); +} + + +void Project::logWarning() +{ + if (logFile.is_open()) + { + logFile << "WARNING! " << errorString.toStdString() << std::endl; + } + + if (modality == MODE_GUI) + { + QMessageBox::warning(nullptr, "WARNING!", errorString); + } + else + { + std::cout << "WARNING! " << errorString.toStdString() << std::endl; + } +} + + void Project::logError() { if (logFile.is_open()) @@ -4483,76 +4589,69 @@ void Project::closeProgressBar() } } -bool Project::findTempMinMax(meteoVariable myVar) -{ - float min; - float max; - float value; - int i = 0; +bool Project::findTemperatureRange(meteoVariable myVar) +{ if (nrMeteoPoints == 0) return false; + // check frequency and variable frequencyType myFreq = getVarFrequency(myVar); - Crit3DDate myDate = getCrit3DDate(this->getCurrentDate()); - int myHour = this->getCurrentHour(); - if (myFreq == daily) { if (myVar != dailyAirTemperatureAvg && myVar != dailyAirTemperatureMax && myVar != dailyAirTemperatureMin) return false; - - do { - min = meteoPoints[i].getMeteoPointValueD(myDate, myVar); - max = min; - i++; - } while (min == NODATA && i < nrMeteoPoints); - - while (i < nrMeteoPoints) - { - value = meteoPoints[i].getMeteoPointValueD(myDate, myVar); - if (value != NODATA) - { - if (value < min) - min = value; - if (value > max) - max = value; - } - i++; - } } else if (myFreq == hourly) { if (myVar != airTemperature) return false; + } + else + { + return false; + } - do { - min = meteoPoints[i].getMeteoPointValueH(myDate, myHour, 0, myVar); - max = min; - i++; - } while (min == NODATA); + Crit3DDate myDate = getCrit3DDate(this->getCurrentDate()); + int myHour = this->getCurrentHour(); + float currentMin = NODATA; + float currentMax = NODATA; + float value = NODATA; - for (int i = 0; i < nrMeteoPoints; i++) + for (int i = 0; i < nrMeteoPoints; i++) + { + if (myFreq == daily) + { + value = meteoPoints[i].getMeteoPointValueD(myDate, myVar); + } + else if (myFreq == hourly) { value = meteoPoints[i].getMeteoPointValueH(myDate, myHour, 0, myVar); - if (value != NODATA) + } + if (value != NODATA) + { + if (value < currentMin || currentMin == NODATA) + { + currentMin = value; + } + if (value > currentMax || currentMax == NODATA) { - if (value < min) - min = value; - if (value > max) - max = value; + currentMax = value; } } } - if (min != NODATA && max != NODATA) - interpolationSettings.setMinMaxTemperature(min, max); + if (currentMin == NODATA || currentMax == NODATA) + { + return false; + } + interpolationSettings.setMinMaxTemperature(currentMin, currentMax); return true; } -bool Project::waterTableImportLocation(QString csvFileName) +bool Project::waterTableImportLocation(const QString &csvFileName) { if (logFileName == "") { @@ -4560,7 +4659,7 @@ bool Project::waterTableImportLocation(QString csvFileName) } int wrongLines = 0; - if (! loadCsvRegistry(csvFileName, wellPoints, errorString, wrongLines)) + if (! loadWaterTableLocationCsv(csvFileName, wellPoints, gisSettings, errorString, wrongLines)) { logError(errorString); return false; @@ -4570,7 +4669,7 @@ bool Project::waterTableImportLocation(QString csvFileName) { logInfo(errorString); QMessageBox::warning(nullptr, "Warning!", QString::number(wrongLines) - + " wrong lines of data were not loaded, see the log file for more information: " + logFileName); + + " wrong lines of data were not loaded\nSee the log file for more information:\n" + logFileName); } errorString = ""; @@ -4578,10 +4677,10 @@ bool Project::waterTableImportLocation(QString csvFileName) } -bool Project::waterTableImportDepths(QString csvDepths) +bool Project::waterTableImportDepths(const QString &csvDepthsFileName) { int wrongLines = 0; - if (! loadCsvDepths(csvDepths, wellPoints, quality->getWaterTableMaximumDepth(), errorString, wrongLines)) + if (! loadWaterTableDepthCsv(csvDepthsFileName, wellPoints, quality->getWaterTableMaximumDepth(), errorString, wrongLines)) { logError(errorString); return false; @@ -4591,7 +4690,7 @@ bool Project::waterTableImportDepths(QString csvDepths) { logInfo(errorString); QMessageBox::warning(nullptr, "Warning!", QString::number(wrongLines) - + " wrong lines of data were not loaded, see the log file for more information: " + logFileName); + + " wrong lines of data were not loaded\nSee the log file for more information:\n" + logFileName); } errorString = ""; @@ -4599,7 +4698,7 @@ bool Project::waterTableImportDepths(QString csvDepths) } -bool Project::computeSingleWell(int indexWell) +bool Project::waterTableComputeSingleWell(int indexWell) { if (indexWell == NODATA) return false; @@ -4609,6 +4708,7 @@ bool Project::computeSingleWell(int indexWell) double wellUtmX = wellPoints[indexWell].getUtmX(); double wellUtmY = wellPoints[indexWell].getUtmY(); Crit3DMeteoPoint linkedMeteoPoint; + if (this->meteoGridDbHandler != nullptr) { isMeteoGridLoaded = true; @@ -4622,38 +4722,60 @@ bool Project::computeSingleWell(int indexWell) logError(ERROR_STR_MISSING_POINT_GRID); return false; } - if (!assignNearestMeteoPoint(isMeteoGridLoaded, wellUtmX, wellUtmY, firstMeteoDate, &linkedMeteoPoint)) + + QString idStr = wellPoints[indexWell].getId(); + if (! waterTableAssignNearestMeteoPoint(isMeteoGridLoaded, wellUtmX, wellUtmY, firstMeteoDate, &linkedMeteoPoint)) { - logError("Missing near weather data"); + logError("Missing weather data near well: " + idStr); return false; } if (linkedMeteoPoint.nrObsDataDaysD == 0) { - logError("Missing near weather data"); + logError("Missing weather data near well: " + idStr); return false; } - int maxNrDays = 730; // attualmente fisso - WaterTable waterTable(&linkedMeteoPoint, *meteoSettings, gisSettings); - waterTable.computeWaterTable(wellPoints[indexWell], maxNrDays); - waterTable.viewWaterTableSeries(); // prepare series to show + + std::vector inputTMin; + std::vector inputTMax; + std::vector inputPrec; + + for (int i = 0; i < linkedMeteoPoint.nrObsDataDaysD; i++) + { + Crit3DDate myDate = linkedMeteoPoint.getFirstDailyData().addDays(i); + float Tmin = linkedMeteoPoint.getMeteoPointValueD(myDate, dailyAirTemperatureMin); + float Tmax = linkedMeteoPoint.getMeteoPointValueD(myDate, dailyAirTemperatureMax); + float prec = linkedMeteoPoint.getMeteoPointValueD(myDate, dailyPrecipitation); + inputTMin.push_back(Tmin); + inputTMax.push_back(Tmax); + inputPrec.push_back(prec); + } + + WaterTable waterTable(inputTMin, inputTMax, inputPrec, getQDate(linkedMeteoPoint.getFirstDailyData()), + getQDate(linkedMeteoPoint.getLastDailyData()), *meteoSettings); + + waterTable.computeWaterTableParameters(wellPoints[indexWell], 5); + + waterTable.computeWaterTableSeries(); // prepare series to show + waterTableList.push_back(waterTable); return true; } -void Project::showSingleWell(WaterTable waterTable, QString idWell) +void Project::waterTableShowSingleWell(WaterTable &waterTable, const QString &idWell) { DialogSummary* dialogResult = new DialogSummary(waterTable); // show results dialogResult->show(); - WaterTableWidget* chartResult = new WaterTableWidget(idWell, waterTable.getMyDates(), waterTable.getMyHindcastSeries(), waterTable.getMyInterpolateSeries(), waterTable.getObsDepths()); + WaterTableWidget* chartResult = new WaterTableWidget(idWell, waterTable, quality->getWaterTableMaximumDepth()); chartResult->show(); return; } -bool Project::assignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, double wellUtmY, QDate firstMeteoDate, Crit3DMeteoPoint* linkedMeteoPoint) + +bool Project::waterTableAssignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, double wellUtmY, QDate firstMeteoDate, Crit3DMeteoPoint* linkedMeteoPoint) { float minimumDistance = NODATA; - bool assignNearestMeteoPoint = false; + bool isFound = false; if (isMeteoGridLoaded) { std::string assignNearestId; @@ -4661,6 +4783,7 @@ bool Project::assignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, d unsigned int assignNearestCol; int zoneNumber; QDate lastDate = this->meteoGridDbHandler->getLastDailyDate(); + QDate firstDate = std::max(firstMeteoDate, this->meteoGridDbHandler->getFirstDailyDate()); for (unsigned row = 0; row < unsigned(meteoGridDbHandler->meteoGrid()->gridStructure().header().nrRows); row++) { for (unsigned col = 0; col < unsigned(meteoGridDbHandler->meteoGrid()->gridStructure().header().nrCols); col++) @@ -4684,16 +4807,16 @@ bool Project::assignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, d assignNearestId = meteoGridDbHandler->meteoGrid()->meteoPointPointer(row,col)->id; assignNearestRow = row; assignNearestCol = col; - assignNearestMeteoPoint = true; + isFound = true; } } } } } - if (assignNearestMeteoPoint) + if (isFound) { - meteoGridDbHandler->loadGridDailyMeteoPrec(errorString, QString::fromStdString(assignNearestId), firstMeteoDate, lastDate); - if (!assignWTMeteoData(meteoGridDbHandler->meteoGrid()->meteoPointPointer(assignNearestRow,assignNearestCol), firstMeteoDate)) + meteoGridDbHandler->loadGridDailyMeteoPrec(errorString, QString::fromStdString(assignNearestId), firstDate, lastDate); + if (! waterTableAssignMeteoData(meteoGridDbHandler->meteoGrid()->meteoPointPointer(assignNearestRow, assignNearestCol), firstDate)) { return false; } @@ -4722,16 +4845,16 @@ bool Project::assignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, d if (myDistance < minimumDistance || minimumDistance == NODATA) { meteoPointsDbHandler->loadDailyData(getCrit3DDate(firstMeteoDate), getCrit3DDate(lastDate), &(meteoPoints[i])); - if (assignWTMeteoData(&meteoPoints[i], firstMeteoDate)) + if (waterTableAssignMeteoData(&meteoPoints[i], firstMeteoDate)) { minimumDistance = myDistance; - assignNearestMeteoPoint = true; + isFound = true; assignNearestIndex = i; } } } } - if (assignNearestMeteoPoint) + if (isFound) { linkedMeteoPoint->id = meteoPoints[assignNearestIndex].id; linkedMeteoPoint->name = meteoPoints[assignNearestIndex].name; @@ -4740,10 +4863,12 @@ bool Project::assignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, d linkedMeteoPoint->obsDataD = meteoPoints[assignNearestIndex].obsDataD; } } - return assignNearestMeteoPoint; + + return isFound; } -bool Project::assignWTMeteoData(Crit3DMeteoPoint* linkedMeteoPoint, QDate firstMeteoDate) + +bool Project::waterTableAssignMeteoData(Crit3DMeteoPoint* linkedMeteoPoint, QDate firstMeteoDate) { QDate lastMeteoDate; lastMeteoDate.setDate(linkedMeteoPoint->getLastDailyData().year, linkedMeteoPoint->getLastDailyData().month, linkedMeteoPoint->getLastDailyData().day); // ultimo dato disponibile @@ -4762,3 +4887,102 @@ bool Project::assignWTMeteoData(Crit3DMeteoPoint* linkedMeteoPoint, QDate firstM return false; } } + + +bool Project::assignAltitudeToAggregationPoints() +{ + if (! DEM.isLoaded) + { + errorString = ERROR_STR_MISSING_DEM; + return false; + } + + if (aggregationDbHandler == nullptr) + { + errorString = "Open or create a new aggregation database before."; + return false; + } + + if (meteoPointsLoaded) + { + errorString = "Close Meteo Points db before execute this operation!"; + return false; + } + + // check aggregation raster + QString rasterName; + if (! aggregationDbHandler->getRasterName(&rasterName)) + { + errorString = "Missing raster name inside aggregation db."; + return false; + } + + QString rasterFileName = aggregationPath + "/" + rasterName; + QFileInfo rasterFileFltInfo(rasterFileName + ".flt"); + QFileInfo rasterFileHdrInfo(rasterFileName + ".hdr"); + if (! rasterFileFltInfo.exists() || ! rasterFileHdrInfo.exists()) + { + errorString = "Raster file does not exist: " + rasterFileName; + return false; + } + + // load aggregation db as meteo points db + if (! loadMeteoPointsDB(aggregationDbHandler->name()) ) + { + errorString = "Error in load aggregation points: " + errorString; + return false; + } + + // load aggregation raster + std::string errorStr = ""; + std::string fileNameStdStr = rasterFileName.toStdString() + ".flt"; + gis::Crit3DRasterGrid *aggregationRaster; + aggregationRaster = new(gis::Crit3DRasterGrid); + if (! gis::openRaster(fileNameStdStr, aggregationRaster, gisSettings.utmZone, errorStr)) + { + errorString = "Open raster failed: " + QString::fromStdString(errorStr); + return false; + } + + // resample aggregation DEM + gis::Crit3DRasterGrid *aggregationDEM; + aggregationDEM = new(gis::Crit3DRasterGrid); + gis::resampleGrid(DEM, aggregationDEM, aggregationRaster->header, aggrAverage, 0.1f); + + setProgressBar("Compute altitude..", nrMeteoPoints); + + // compute average altitude from aggregation DEM + for (int i = 0; i < nrMeteoPoints; i++) + { + QString idStr = QString::fromStdString(meteoPoints[i].id); + QList idList = idStr.split('_'); + float zoneNr = idList[0].toFloat(); + + std::vector values; + for (int row = 0; row < aggregationRaster->header->nrRows; row++) + { + for (int col = 0; col < aggregationRaster->header->nrCols; col++) + { + if (isEqual(aggregationRaster->value[row][col], zoneNr)) + { + float z = aggregationDEM->value[row][col]; + if (! isEqual(z, aggregationDEM->header->flag)) + { + values.push_back(z); + } + } + } + } + + // update point properties + float altitude = statistics::mean(values); + QString query = QString("UPDATE point_properties SET altitude = %1 WHERE id_point = '%2'").arg(altitude).arg(idStr); + aggregationDbHandler->db().exec(query); + + updateProgressBar(i); + } + + closeMeteoPointsDB(); + return true; +} + diff --git a/agrolib/project/project.h b/agrolib/project/project.h index 7c0f60f5..30f833b9 100644 --- a/agrolib/project/project.h +++ b/agrolib/project/project.h @@ -59,7 +59,7 @@ #define ERROR_STR_MISSING_DEM "Load a Digital Elevation Model (DEM) before." #define ERROR_STR_MISSING_PROJECT "Open a project before." #define ERROR_STR_MISSING_GRID "Load a meteo grid DB before." - #define ERROR_STR_MISSING_POINT_GRID "Load meteo Points or grid." + #define ERROR_STR_MISSING_POINT_GRID "Load meteo points or meteo grid before." class Crit3DMeteoWidget; class FormInfo; @@ -181,7 +181,7 @@ void setProxyDEM(); void clearProxyDEM(); - bool checkProxy(const Crit3DProxy &myProxy, QString *error); + bool checkProxy(Crit3DProxy &myProxy, QString *error); bool addProxyToProject(std::vector proxyList, std::deque proxyActive, std::vector proxyOrder); void addProxyGridSeries(QString name_, std::vector gridNames, std::vector gridYears); void setCurrentDate(QDate myDate); @@ -203,12 +203,17 @@ QString getCompleteFileName(QString fileName, QString secondaryPath); bool setLogFile(QString myFileName); - void logError(QString myStr); + void logInfo(QString myStr); void logInfoGUI(QString myStr); void closeLogInfo(); + + void logError(QString myStr); void logError(); + void logWarning(QString myStr); + void logWarning(); + int setProgressBar(QString myStr, int nrValues); void updateProgressBar(int value); void updateProgressBarText(QString myStr); @@ -236,6 +241,7 @@ bool loadMeteoGridHourlyData(QDateTime firstDate, QDateTime lastDate, bool showInfo); bool loadMeteoGridMonthlyData(QDate firstDate, QDate lastDate, bool showInfo); void loadMeteoGridData(QDate firstDate, QDate lastDate, bool showInfo); + QDateTime findDbPointLastTime(); QDateTime findDbPointFirstTime(); @@ -262,7 +268,8 @@ bool interpolationOutputPoints(std::vector &interpolationPoints, gis::Crit3DRasterGrid *outputGrid, meteoVariable myVar); bool interpolationCv(meteoVariable myVar, const Crit3DTime& myTime, crossValidationStatistics* myStats); - bool computeStatisticsCrossValidation(Crit3DTime myTime, meteoVariable myVar, crossValidationStatistics *myStats); + + bool computeStatisticsCrossValidation(crossValidationStatistics *myStats); bool meteoGridAggregateProxy(std::vector &myGrids); frequencyType getCurrentFrequency() const; @@ -277,7 +284,7 @@ void showMeteoWidgetGrid(std::string idCell, bool isAppend); void showProxyGraph(); void showLocalProxyGraph(gis::Crit3DGeoPoint myPoint, gis::Crit3DRasterGrid *myDataRaster); - bool findTempMinMax(meteoVariable myVar); + bool findTemperatureRange(meteoVariable myVar); void clearSelectedPoints(); void clearSelectedOutputPoints(); @@ -300,12 +307,14 @@ void setComputeOnlyPoints(bool value); bool getComputeOnlyPoints(); - bool waterTableImportLocation(QString csvFileName); - bool waterTableImportDepths(QString csvDepths); - bool computeSingleWell(int indexWell); - void showSingleWell(WaterTable waterTable, QString idWell); - bool assignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, double wellUtmY, QDate firstMeteoDate, Crit3DMeteoPoint* linkedMeteoPoint); - bool assignWTMeteoData(Crit3DMeteoPoint* linkedMeteoPoint, QDate firstMeteoDate); + bool waterTableImportLocation(const QString &csvFileName); + bool waterTableImportDepths(const QString &csvDepthsFileName); + bool waterTableComputeSingleWell(int indexWell); + void waterTableShowSingleWell(WaterTable &waterTable, const QString &idWell); + bool waterTableAssignNearestMeteoPoint(bool isMeteoGridLoaded, double wellUtmX, double wellUtmY, QDate firstMeteoDate, Crit3DMeteoPoint* linkedMeteoPoint); + bool waterTableAssignMeteoData(Crit3DMeteoPoint* linkedMeteoPoint, QDate firstMeteoDate); + + bool assignAltitudeToAggregationPoints(); private slots: void deleteMeteoWidgetPoint(int id); diff --git a/agrolib/project/project.pro b/agrolib/project/project.pro index b6188538..dca5f276 100644 --- a/agrolib/project/project.pro +++ b/agrolib/project/project.pro @@ -31,7 +31,7 @@ INCLUDEPATH += ../crit3dDate ../mathFunctions ../gis ../meteo \ ../solarRadiation ../interpolation ../utilities \ ../netcdfHandler ../dbMeteoPoints ../outputPoints ../dbMeteoGrid \ ../meteoWidget ../commonDialogs ../commonChartElements ../climate \ - ../proxyWidget ../inOutDataXML ../waterTable + ../proxyWidget ../waterTable SOURCES += \ diff --git a/agrolib/project/shell.cpp b/agrolib/project/shell.cpp index c2be7f5d..9230ddcc 100644 --- a/agrolib/project/shell.cpp +++ b/agrolib/project/shell.cpp @@ -3,6 +3,7 @@ #include "project.h" #include "shell.h" #include "dbMeteoGrid.h" +#include "utilities.h" #include #include @@ -382,6 +383,14 @@ int cmdExportDailyDataCsv(Project* myProject, QList argumentList) QString completeOutputPath = myProject->getProjectPath() + outputPath; outputPath = QDir().cleanPath(completeOutputPath); } + else + { + if(getFileName(outputPath) == outputPath) + { + QString completeOutputPath = myProject->getProjectPath() + PATH_OUTPUT + outputPath; + outputPath = QDir().cleanPath(completeOutputPath); + } + } } } } @@ -431,8 +440,8 @@ int cmdExportDailyDataCsv(Project* myProject, QList argumentList) return PRAGA_ERROR; } - if (! myProject->meteoGridDbHandler->exportDailyDataCsv(myProject->errorString, variableList, - firstDate, lastDate, idListFileName, outputPath)) + if (! myProject->meteoGridDbHandler->exportDailyDataCsv(variableList, firstDate, lastDate, + idListFileName, outputPath, myProject->errorString)) { myProject->logError(); return PRAGA_ERROR; diff --git a/agrolib/proxyWidget/localProxyWidget.cpp b/agrolib/proxyWidget/localProxyWidget.cpp index 74649656..181a0180 100644 --- a/agrolib/proxyWidget/localProxyWidget.cpp +++ b/agrolib/proxyWidget/localProxyWidget.cpp @@ -1,34 +1,9 @@ -/*! - CRITERIA3D - \copyright 2016 Fausto Tomei, Gabriele Antolini, Laura Costantini - Alberto Pistocchi, Marco Bittelli, Antonio Volta - You should have received a copy of the GNU General Public License - along with Nome-Programma. If not, see . - This file is part of CRITERIA3D. - CRITERIA3D has been developed under contract issued by A.R.P.A. Emilia-Romagna - CRITERIA3D is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - CRITERIA3D 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 Lesser General Public License for more details. - You should have received a copy of the /NU Lesser General Public License - along with CRITERIA3D. If not, see . - contacts: - fausto.tomei@gmail.com - ftomei@arpae.it -*/ - #include "meteo.h" #include "localProxyWidget.h" -#include "proxyWidget.h" #include "utilities.h" #include "interpolation.h" #include "spatialControl.h" #include "commonConstants.h" -#include "formInfo.h" #include "math.h" #include "furtherMathFunctions.h" @@ -62,7 +37,12 @@ Crit3DLocalProxyWidget::Crit3DLocalProxyWidget(double x, double y, std::vectoraddWidget(&detrended); selectionOptionBoxLayout->addWidget(&modelLR); selectionOptionBoxLayout->addWidget(&climatologicalLR); + selectionOptionBoxLayout->addWidget(&stationWeights); selectionOptionEditLayout->addWidget(r2Label); selectionOptionEditLayout->addWidget(&r2); @@ -140,43 +121,7 @@ Crit3DLocalProxyWidget::Crit3DLocalProxyWidget(double x, double y, std::vectoraddStretch(30); selectionLayout->addLayout(selectionOptionLayout); - if (!parameters.empty() && interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == frei && parameters[proxyPos].size() == 5) - { - QVBoxLayout *parametriLayout = new QVBoxLayout(); - - QLabel *freiT0Lab = new QLabel(QString("T0: %1").arg(parameters[proxyPos][0])); - QLabel *freiGammaLab = new QLabel(QString("Gamma: %1").arg(parameters[proxyPos][1])); - QLabel *freiALab = new QLabel(QString("a: %1").arg(parameters[proxyPos][2])); - QLabel *freiH0Lab = new QLabel(QString("H0: %1").arg(parameters[proxyPos][3])); - QLabel *freiH1Lab = new QLabel(QString("H1: %1").arg(parameters[proxyPos][4]+parameters[proxyPos][3])); - - parametriLayout->addWidget(freiT0Lab); - parametriLayout->addWidget(freiGammaLab); - parametriLayout->addWidget(freiALab); - parametriLayout->addWidget(freiH0Lab); - parametriLayout->addWidget(freiH1Lab); - - selectionLayout->addLayout(parametriLayout); - } - else if (!parameters.empty() && interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThree && parameters[proxyPos].size() == 5) - { - QVBoxLayout *parametriLayout = new QVBoxLayout(); - - QLabel *H0Lab = new QLabel(QString("H0: %1").arg(parameters[proxyPos][0])); - QLabel *T0Lab = new QLabel(QString("T0: %1").arg(parameters[proxyPos][1])); - QLabel *H1Lab = new QLabel(QString("H1: %1").arg(parameters[proxyPos][0]+parameters[proxyPos][2])); - QLabel *T1Lab = new QLabel(QString("T1: %1").arg(parameters[proxyPos][1]+parameters[proxyPos][3])); - QLabel *slopeLab = new QLabel(QString("slope: %1").arg(parameters[proxyPos][4])); - - parametriLayout->addWidget(H0Lab); - parametriLayout->addWidget(T0Lab); - parametriLayout->addWidget(H1Lab); - parametriLayout->addWidget(T1Lab); - parametriLayout->addWidget(slopeLab); - - selectionLayout->addLayout(parametriLayout); - } - else if (!parameters.empty() && interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseTwo && parameters[proxyPos].size() == 4) + if (!parameters.empty() && interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseTwo && parameters[proxyPos].size() == 4) { QVBoxLayout *parametriLayout = new QVBoxLayout(); @@ -213,7 +158,7 @@ Crit3DLocalProxyWidget::Crit3DLocalProxyWidget(double x, double y, std::vectoraddLayout(parametriLayout); } - else if (!parameters.empty() && interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThreeSlope && parameters[proxyPos].size() == 5) + else if (!parameters.empty() && interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThree && parameters[proxyPos].size() == 5) { QVBoxLayout *parametriLayout = new QVBoxLayout(); @@ -260,6 +205,7 @@ Crit3DLocalProxyWidget::Crit3DLocalProxyWidget(double x, double y, std::vectorclimatologicalLRClicked(toggled); }); connect(&modelLR, &QCheckBox::toggled, [=](int toggled){ this->modelLRClicked(toggled); }); connect(&detrended, &QCheckBox::toggled, [=](){ this->plot(); }); + connect(&stationWeights, &QCheckBox::toggled, [=] () {this->plot();}); connect(updateStations, &QAction::triggered, this, [=](){ this->plot(); }); if (currentFrequency != noFrequency) @@ -389,6 +335,14 @@ void Crit3DLocalProxyWidget::plot() outInterpolationPoints.clear(); subsetInterpolationPoints.clear(); std::string errorStdStr; + + for (QGraphicsTextItem* label : weightLabels) + { + chartView->scene()->removeItem(label); + delete label; + } + weightLabels.clear(); + if (detrended.isChecked()) { outInterpolationPoints.clear(); @@ -397,7 +351,7 @@ void Crit3DLocalProxyWidget::plot() interpolationSettings, meteoSettings, climateParam, outInterpolationPoints, checkSpatialQuality, errorStdStr); - localSelection(outInterpolationPoints, subsetInterpolationPoints, x, y, *interpolationSettings); + localSelection(outInterpolationPoints, subsetInterpolationPoints, x, y, z, *interpolationSettings); detrending(subsetInterpolationPoints, interpolationSettings->getSelectedCombination(), interpolationSettings, climateParam, myVar, getCurrentTime()); } else @@ -405,7 +359,7 @@ void Crit3DLocalProxyWidget::plot() checkAndPassDataToInterpolation(quality, myVar, meteoPoints, nrMeteoPoints, getCurrentTime(), SQinterpolationSettings, interpolationSettings, meteoSettings, climateParam, outInterpolationPoints, checkSpatialQuality, errorStdStr); - localSelection(outInterpolationPoints, subsetInterpolationPoints, x, y, *interpolationSettings); + localSelection(outInterpolationPoints, subsetInterpolationPoints, x, y, z, *interpolationSettings); } QList pointListPrimary, pointListSecondary, pointListSupplemental, pointListMarked; QMap< QString, QPointF > idPointMap1; @@ -424,7 +378,8 @@ void Crit3DLocalProxyWidget::plot() point.setX(proxyVal); point.setY(varValue); QString text = "id: " + QString::fromStdString(meteoPoints[subsetInterpolationPoints[i].index].id) + "\n" - + "name: " + QString::fromStdString(meteoPoints[subsetInterpolationPoints[i].index].name); + + "name: " + QString::fromStdString(meteoPoints[subsetInterpolationPoints[i].index].name) + "\n" + + "weight: " + QString::number(subsetInterpolationPoints[i].regressionWeight, 'f', 5); if (subsetInterpolationPoints[i].isMarked) { pointListMarked.append(point); @@ -502,6 +457,37 @@ void Crit3DLocalProxyWidget::plot() { modelLRClicked(1); } + + if (stationWeights.isChecked()) + { + QChart* chart = chartView->chart(); + QRectF chartRect = chart->plotArea(); + double xMin = chartView->axisX->min(); + double xMax = chartView->axisX->max(); + double yMin = chartView->axisY->min(); + double yMax = chartView->axisY->max(); + + for (int i = 0; i < int(subsetInterpolationPoints.size()); i++) + { + float proxyVal = subsetInterpolationPoints[i].getProxyValue(proxyPos); + float varValue = subsetInterpolationPoints[i].value; + + if (proxyVal != NODATA && varValue != NODATA) + { + double xRatio = (proxyVal - xMin) / (xMax - xMin); + double yRatio = (varValue - yMin) / (yMax - yMin); + + QPointF scenePos; + scenePos.setX(chartRect.left() + xRatio * chartRect.width()); + scenePos.setY(chartRect.bottom() - yRatio * chartRect.height()); + + QGraphicsTextItem* weightLabel = new QGraphicsTextItem(QString::number(subsetInterpolationPoints[i].regressionWeight, 'f', 3)); + weightLabel->setPos(scenePos); + chartView->scene()->addItem(weightLabel); + weightLabels.push_back(weightLabel); + } + } + } } @@ -539,171 +525,94 @@ void Crit3DLocalProxyWidget::modelLRClicked(int toggled) if (toggled && subsetInterpolationPoints.size() != 0 && currentVariable == myVar) { - if (comboAxisX.currentText() == "elevation") + if (parameters.size() > proxyPos) { - xMin = getZmin(subsetInterpolationPoints); - xMax = getZmax(subsetInterpolationPoints); - float myY; - - if (interpolationSettings->getUseMultipleDetrending()) + if (parameters[proxyPos].size() > 2) { - if (parameters.empty() || (parameters[proxyPos].size() != 5 && parameters[proxyPos].size() != 6 && parameters[proxyPos].size() != 4)) - return; + xMin = getZmin(subsetInterpolationPoints); + xMax = getZmax(subsetInterpolationPoints); + float myY; - if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThree) + if (interpolationSettings->getUseMultipleDetrending()) { - float lapseRateH0 = parameters[proxyPos][0]; - float lapseRateH1 = parameters[proxyPos][0]+parameters[proxyPos][2]; - float lapseRateT0 = parameters[proxyPos][1]; - float lapseRateT1 = parameters[proxyPos][1]+parameters[proxyPos][3]; - float regressionSlope = parameters[proxyPos][4]; + if ((parameters[proxyPos].size() != 5 && parameters[proxyPos].size() != 6 && parameters[proxyPos].size() != 4)) + return; - if (xMin < lapseRateH0) + if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThree) { - myY = lapseRateT0 + regressionSlope * (xMin - lapseRateH0); - point.setX(xMin); - point.setY(myY); - point_vector.append(point); + std::vector xVector; + for (int m = xMin; m < xMax; m += 5) + xVector.push_back(m); + + for (int p = 0; p < int(xVector.size()); p++) + { + point.setX(xVector[p]); + point.setY(lapseRatePiecewise_three(xVector[p], parameters[proxyPos])); + point_vector.append(point); + } } - - point.setX(lapseRateH0); - point.setY(lapseRateT0); - point_vector.append(point); - - point.setX(lapseRateH1); - point.setY(lapseRateT1); - point_vector.append(point); - - if (xMax > lapseRateH1) + else if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseTwo) { - myY = lapseRateT1 + regressionSlope * (xMax - lapseRateH1); - point.setX(xMax); - point.setY(myY); + float lapseRateH0 = parameters[proxyPos][0]; + float lapseRateT0 = parameters[proxyPos][1]; + float slope1 = parameters[proxyPos][2]; + float slope2 = parameters[proxyPos][3]; + + if (xMin < lapseRateH0) + { + myY = lapseRateT0 + slope1 * (xMin - lapseRateH0); + point.setX(xMin); + point.setY(myY); + point_vector.append(point); + } + + point.setX(lapseRateH0); + point.setY(lapseRateT0); point_vector.append(point); - } - } - else if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseTwo) - { - float lapseRateH0 = parameters[proxyPos][0]; - float lapseRateT0 = parameters[proxyPos][1]; - float slope1 = parameters[proxyPos][2]; - float slope2 = parameters[proxyPos][3]; - if (xMin < lapseRateH0) - { - myY = lapseRateT0 + slope1 * (xMin - lapseRateH0); - point.setX(xMin); + myY = lapseRateT0 + slope2 * (xMax - lapseRateH0); + point.setX(xMax); point.setY(myY); point_vector.append(point); } - - point.setX(lapseRateH0); - point.setY(lapseRateT0); - point_vector.append(point); - - myY = lapseRateT0 + slope2 * (xMax - lapseRateH0); - point.setX(xMax); - point.setY(myY); - point_vector.append(point); - } - else if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == frei) - { - std::vector xVector; - for (int m = xMin; m < xMax; m += 5) - xVector.push_back(m); - - for (int p = 0; p < xVector.size(); p++) + else if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThreeFree) { - point.setX(xVector[p]); - point.setY(lapseRateFrei(xVector[p], parameters[proxyPos])); - point_vector.append(point); - } - } - else if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThreeFree) - { - std::vector xVector; - for (int m = xMin; m < xMax; m += 5) - xVector.push_back(m); + std::vector xVector; + for (int m = xMin; m < xMax; m += 5) + xVector.push_back(m); - for (int p = 0; p < xVector.size(); p++) - { - point.setX(xVector[p]); - point.setY(lapseRatePiecewiseFree(xVector[p], parameters[proxyPos])); - point_vector.append(point); - } - } - else if (interpolationSettings->getProxy(proxyPos)->getFittingFunctionName() == piecewiseThreeSlope) - { - std::vector xVector; - for (int m = xMin; m < xMax; m += 5) - xVector.push_back(m); + for (int p = 0; p < int(xVector.size()); p++) + { + point.setX(xVector[p]); + point.setY(lapseRatePiecewise_three_free(xVector[p], parameters[proxyPos])); + point_vector.append(point); + } - for (int p = 0; p < xVector.size(); p++) - { - point.setX(xVector[p]); - point.setY(lapseRatePiecewiseThree_withSlope(xVector[p], parameters[proxyPos])); - point_vector.append(point); } - } - /*if (interpolationSettings->getProxy(proxyPos)->getInversionIsSignificative()) - { - if (xMin < interpolationSettings->getProxy(proxyPos)->getLapseRateH0()) - { - point.setX(xMin); - point.setY(lapseRateT0); - point_vector.append(point); - }*/ - + } + else + { + xMin = getProxyMinValue(subsetInterpolationPoints, proxyPos); + xMax = getProxyMaxValue(subsetInterpolationPoints, proxyPos); - /*} - else - { - float myY = lapseRateT0 + regressionSlope * xMin; - point.setX(xMin); - point.setY(myY); - point_vector.append(point); + if (parameters[proxyPos].empty()) + return; - myY = lapseRateT0 + regressionSlope * xMax; - point.setX(xMax); - point.setY(myY); - point_vector.append(point); - }*/ + float slope = parameters[proxyPos][0]; + float intercept = parameters[proxyPos][1]; - } + float myY = intercept + slope * xMin; + point.setX(xMin); + point.setY(myY); + point_vector.append(point); - /*if (interpolationSettings->getProxy(proxyPos)->getRegressionR2() != NODATA) - { - r2.setText(QString("%1").arg(interpolationSettings->getProxy(proxyPos)->getRegressionR2(), 0, 'f', 2)); + myY = intercept + slope * xMax; + point.setX(xMax); + point.setY(myY); + point_vector.append(point); } - lapseRate.setText(QString("%1").arg(regressionSlope*1000, 0, 'f', 2));*/ } - else - { - //TODO lineari - /*xMin = getProxyMinValue(subsetInterpolationPoints, proxyPos); - xMax = getProxyMaxValue(subsetInterpolationPoints, proxyPos); - bool isZeroIntercept = false; - if (!regressionGeneric(subsetInterpolationPoints, interpolationSettings, proxyPos, isZeroIntercept)) - { - return; - } - float regressionSlope = interpolationSettings->getProxy(proxyPos)->getRegressionSlope(); - float regressionIntercept = interpolationSettings->getProxy(proxyPos)->getRegressionIntercept(); - point.setX(xMin); - point.setY(regressionIntercept + regressionSlope * xMin); - point_vector.append(point); - point.setX(xMax); - point.setY(regressionIntercept + regressionSlope * xMax); - point_vector.append(point); - - float regressionR2 = interpolationSettings->getProxy(proxyPos)->getRegressionR2(); - if (regressionR2 != NODATA) - { - r2.setText(QString("%1").arg(regressionR2, 0, 'f', 2)); - } - lapseRate.setText(QString("%1").arg(regressionSlope, 0, 'f', 2)); - */ } chartView->drawModelLapseRate(point_vector); } } diff --git a/agrolib/proxyWidget/localProxyWidget.h b/agrolib/proxyWidget/localProxyWidget.h index a367eae6..63a291ba 100644 --- a/agrolib/proxyWidget/localProxyWidget.h +++ b/agrolib/proxyWidget/localProxyWidget.h @@ -23,10 +23,10 @@ class Crit3DLocalProxyWidget : public QWidget void plot(); void climatologicalLRClicked(int toggled); void modelLRClicked(int toggled); - private: double x; double y; + double z; std::vector> parameters; gis::Crit3DGisSettings gisSettings; Crit3DInterpolationSettings* interpolationSettings; @@ -48,11 +48,13 @@ class Crit3DLocalProxyWidget : public QWidget QCheckBox detrended; QCheckBox climatologicalLR; QCheckBox modelLR; + QCheckBox stationWeights; QTextEdit r2; QTextEdit lapseRate; ChartView *chartView; meteoVariable myVar; int proxyPos; + std::vector weightLabels; Crit3DTime getCurrentTime(); diff --git a/agrolib/proxyWidget/proxyWidget.cpp b/agrolib/proxyWidget/proxyWidget.cpp index 1961b967..8f0d0e55 100644 --- a/agrolib/proxyWidget/proxyWidget.cpp +++ b/agrolib/proxyWidget/proxyWidget.cpp @@ -1,33 +1,9 @@ -/*! - CRITERIA3D - \copyright 2016 Fausto Tomei, Gabriele Antolini, Laura Costantini - Alberto Pistocchi, Marco Bittelli, Antonio Volta - You should have received a copy of the GNU General Public License - along with Nome-Programma. If not, see . - This file is part of CRITERIA3D. - CRITERIA3D has been developed under contract issued by A.R.P.A. Emilia-Romagna - CRITERIA3D is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - CRITERIA3D 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 Lesser General Public License for more details. - You should have received a copy of the /NU Lesser General Public License - along with CRITERIA3D. If not, see . - contacts: - fausto.tomei@gmail.com - ftomei@arpae.it -*/ - #include "meteo.h" #include "proxyWidget.h" #include "utilities.h" #include "interpolation.h" #include "spatialControl.h" #include "commonConstants.h" -#include "formInfo.h" #include "math.h" #include diff --git a/agrolib/soil/soil.cpp b/agrolib/soil/soil.cpp index 87e42a3e..8806509e 100644 --- a/agrolib/soil/soil.cpp +++ b/agrolib/soil/soil.cpp @@ -1,5 +1,5 @@ /*! - CRITERIA3D + soil.cpp \copyright 2016 Fausto Tomei, Gabriele Antolini, Alberto Pistocchi, Marco Bittelli, Antonio Volta, Laura Costantini @@ -353,7 +353,14 @@ namespace soil else { // FINE grained soils - if (horizon.texture.classNameUSDA == "loam" || horizon.texture.classNameUSDA == "clayloam" || horizon.texture.classNameUSDA == "silty clayloam") + if (horizon.texture.classNameUSDA == "loam") + { + if (horizon.organicMatter > 0.2) + return 16; // OL + else + return 12; // SC-CL + } + if (horizon.texture.classNameUSDA == "clayloam" || horizon.texture.classNameUSDA == "silty clayloam") { if (horizon.organicMatter > 0.2) return 16; // OL @@ -365,7 +372,12 @@ namespace soil if (horizon.organicMatter > 0.2) return 16; // OL else - return 13; // ML + { + if(horizon.texture.clay >= 20) + return 12; // SC-CL + else + return 13; // ML + } } if (horizon.texture.classNameUSDA == "clay" || horizon.texture.classNameUSDA == "silty clay") { @@ -379,11 +391,10 @@ namespace soil if (horizon.organicMatter > 0.2) return 16; // OL else - return 14; // CL + return 13; // ML } } - double estimateSpecificDensity(double organicMatter) { if (int(organicMatter) == int(NODATA)) @@ -752,8 +763,8 @@ namespace soil { double suctionStress = -waterPotential * getDegreeOfSaturation(); // [kPa] - double slopeAngle = asin(slope); - double frictionAngle = horizonPtr->frictionAngle * DEG_TO_RAD; + double slopeAngle = std::max(asin(slope), EPSILON); // [rad] + double frictionAngle = horizonPtr->frictionAngle * DEG_TO_RAD; // [rad] double tanAngle = tan(slopeAngle); double tanFrictionAngle = tan(frictionAngle); @@ -780,8 +791,8 @@ namespace soil // surface 2% if (upperDepth == 0.0) return 0.02; // first layer 1% - if (upperDepth > 0 && upperDepth < 0.5) return 0.01; - // sub-surface 0.5% + if (upperDepth > 0 && upperDepth < 0.4) return 0.01; + // sub-surface return MINIMUM_ORGANIC_MATTER; } @@ -814,7 +825,7 @@ namespace soil horizon.texture.silt = horizon.dbData.silt; horizon.texture.clay = horizon.dbData.clay; if (! isEqual(horizon.texture.sand, NODATA) && ! isEqual(horizon.texture.silt, NODATA) && ! isEqual(horizon.texture.clay, NODATA) - && (horizon.texture.sand + horizon.texture.silt + horizon.texture.clay) <= 1 ) + && (horizon.texture.sand + horizon.texture.silt + horizon.texture.clay) <= 1.01 ) { horizon.texture.sand *= 100; horizon.texture.silt *= 100; @@ -927,8 +938,10 @@ namespace soil horizon.CEC = 50.0; horizon.PH = 7.7; - // new parameters for slope stability + // USCS: Unified Soil Classification System horizon.texture.classUSCS = getUSCSClass(horizon); + + // parameters for slope stability if (horizon.dbData.effectiveCohesion != NODATA) { horizon.effectiveCohesion = horizon.dbData.effectiveCohesion; diff --git a/agrolib/soil/soil.h b/agrolib/soil/soil.h index 6f80b0f5..a889c10e 100644 --- a/agrolib/soil/soil.h +++ b/agrolib/soil/soil.h @@ -134,14 +134,14 @@ double upperDepth, lowerDepth; /*!< [m] */ double coarseFragments; /*!< [-] 0-1 */ double organicMatter; /*!< [-] 0-1 */ - double bulkDensity; /*!< [g/cm^3] */ + double bulkDensity; /*!< [g cm-3] */ double effectiveCohesion; /*!< [kPa] */ double frictionAngle; /*!< [degrees] */ double fieldCapacity; /*!< [kPa] */ double wiltingPoint; /*!< [kPa] */ - double waterContentFC; /*!< [m^3 m^-3]*/ - double waterContentWP; /*!< [m^3 m^-3]*/ + double waterContentFC; /*!< [m3 m-3]*/ + double waterContentWP; /*!< [m3 m-3]*/ double PH; /*!< [-] */ double CEC; /*!< [meq/100g]*/ @@ -150,6 +150,7 @@ Crit3DVanGenuchten vanGenuchten; Crit3DWaterConductivity waterConductivity; Crit3DDriessen Driessen; + Crit3DGeotechnicsClass geotechnics; Crit3DHorizon(); diff --git a/agrolib/soil/soilDbTools.cpp b/agrolib/soil/soilDbTools.cpp index 06fd0a3a..1cbb95a7 100644 --- a/agrolib/soil/soilDbTools.cpp +++ b/agrolib/soil/soilDbTools.cpp @@ -1,6 +1,7 @@ #include "soil.h" #include "soilDbTools.h" #include "commonConstants.h" +#include "basicMath.h" #include "utilities.h" #include @@ -275,6 +276,13 @@ bool loadSoilData(const QSqlDatabase &dbSoil, const QString &soilCode, soil::Cri getValue(query.value("sand"), &sand); getValue(query.value("silt"), &silt); getValue(query.value("clay"), &clay); + // check + if (! isEqual(sand, NODATA) && ! isEqual(silt, NODATA) && ! isEqual(clay, NODATA) && (sand + silt + clay) <= 1.01) + { + sand *= 100; + silt *= 100; + clay *= 100; + } mySoil.horizon[i].dbData.sand = sand; mySoil.horizon[i].dbData.silt = silt; mySoil.horizon[i].dbData.clay = clay; @@ -297,7 +305,7 @@ bool loadSoilData(const QSqlDatabase &dbSoil, const QString &soilCode, soil::Cri getValue(query.value("k_sat"), &ksat); mySoil.horizon[i].dbData.kSat = ksat; - // NEW fields for soil stability, not present in old databases + // NEW fields for slope stability, not present in old databases QList fieldList = getFields(query); double value = NODATA; diff --git a/agrolib/soilFluxes3D/boundary.cpp b/agrolib/soilFluxes3D/boundary.cpp index 270b7dbc..c41e7d7e 100644 --- a/agrolib/soilFluxes3D/boundary.cpp +++ b/agrolib/soilFluxes3D/boundary.cpp @@ -195,8 +195,9 @@ double getSurfaceWaterFraction(int i) return 0.0; else { - double h = MAXVALUE(nodeListPtr[i].H - double(nodeListPtr[i].z), 0); - return 1.0 - MAXVALUE(0.0, nodeListPtr[i].Soil->Pond - h) / nodeListPtr[i].Soil->Pond; + double h = std::max(nodeListPtr[i].H - nodeListPtr[i].z, 0.); // [m] + double h0 = std::max(double(nodeListPtr[i].pond), 0.001); // [m] + return h / h0; } } @@ -251,8 +252,9 @@ void updateBoundaryWater (double deltaT) if (nodeListPtr[i].boundary->type == BOUNDARY_RUNOFF) { double avgH = (nodeListPtr[i].H + nodeListPtr[i].oldH) * 0.5; // [m] + // Surface water available for runoff [m] - double hs = MAXVALUE(avgH - (nodeListPtr[i].z + nodeListPtr[i].Soil->Pond), 0.0); + double hs = MAXVALUE(avgH - (nodeListPtr[i].z + nodeListPtr[i].pond), 0.); if (hs > EPSILON_METER) { double maxFlow = (hs * nodeListPtr[i].volume_area) / deltaT; // [m3 s-1] maximum flow available during the time step @@ -383,7 +385,7 @@ void updateBoundaryWater (double deltaT) flow = weight * pressureFlow + (1. - weight) * ManningFlow; } - else if (waterLevel > nodeListPtr[i].Soil->Pond) + else if (waterLevel > nodeListPtr[i].pond) { // open channel flow double boundaryArea = myCulvert.width * waterLevel; // [m^2] diff --git a/agrolib/soilFluxes3D/header/soilFluxes3D.h b/agrolib/soilFluxes3D/header/soilFluxes3D.h index 5f509a39..d9724bc9 100644 --- a/agrolib/soilFluxes3D/header/soilFluxes3D.h +++ b/agrolib/soilFluxes3D/header/soilFluxes3D.h @@ -45,33 +45,36 @@ __EXTERN int DLL_EXPORT __STDCALL setNodeSoil(long nodeIndex, int soilIndex, int horizonIndex); // SURFACE - __EXTERN int DLL_EXPORT __STDCALL setSurfaceProperties(int surfaceIndex, double Roughness, double minWaterLevelRunoff); + __EXTERN int DLL_EXPORT __STDCALL setSurfaceProperties(int surfaceIndex, double Roughness); __EXTERN int DLL_EXPORT __STDCALL setNodeSurface(long nodeIndex, int surfaceIndex); + __EXTERN int DLL_EXPORT __STDCALL setNodePond(long nodeIndex, float pond); // WATER - __EXTERN int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, int conductivityMeanType, float horizVertRatioConductivity); + __EXTERN int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, int conductivityMeanType, float conductivityHorizVertRatio); __EXTERN int DLL_EXPORT __STDCALL setWaterContent(long index, double myWaterContent); - __EXTERN int DLL_EXPORT __STDCALL setMatricPotential(long index, double potential); + __EXTERN int DLL_EXPORT __STDCALL setDegreeOfSaturation(long nodeIndex, double degreeOfSaturation); + __EXTERN int DLL_EXPORT __STDCALL setMatricPotential(long index, double psi); __EXTERN int DLL_EXPORT __STDCALL setTotalPotential(long index, double totalPotential); __EXTERN int DLL_EXPORT __STDCALL setPrescribedTotalPotential(long index, double prescribedTotalPotential); __EXTERN int DLL_EXPORT __STDCALL setWaterSinkSource(long index, double sinkSource); - __EXTERN double DLL_EXPORT __STDCALL getWaterContent(long index); - __EXTERN double DLL_EXPORT __STDCALL getAvailableWaterContent(long index); + __EXTERN double DLL_EXPORT __STDCALL getWaterContent(long nodeIndex); + __EXTERN double DLL_EXPORT __STDCALL getAvailableWaterContent(long nodeIndex); __EXTERN double DLL_EXPORT __STDCALL getWaterDeficit(long index, double fieldCapacity); __EXTERN double DLL_EXPORT __STDCALL getTotalWaterContent(); - __EXTERN double DLL_EXPORT __STDCALL getDegreeOfSaturation(long index); - __EXTERN double DLL_EXPORT __STDCALL getBoundaryWaterFlow(long index); + __EXTERN double DLL_EXPORT __STDCALL getDegreeOfSaturation(long nodeIndex); + __EXTERN double DLL_EXPORT __STDCALL getBoundaryWaterFlow(long nodeIndex); __EXTERN double DLL_EXPORT __STDCALL getBoundaryWaterSumFlow(int boundaryType); - __EXTERN double DLL_EXPORT __STDCALL getMatricPotential(long index); - __EXTERN double DLL_EXPORT __STDCALL getTotalPotential(long index); + __EXTERN double DLL_EXPORT __STDCALL getMatricPotential(long nodeIndex); + __EXTERN double DLL_EXPORT __STDCALL getTotalPotential(long nodeIndex); __EXTERN double DLL_EXPORT __STDCALL getWaterMBR(); - __EXTERN double DLL_EXPORT __STDCALL getWaterConductivity(long index); - __EXTERN double DLL_EXPORT __STDCALL getWaterFlow(long index, short direction); - __EXTERN double DLL_EXPORT __STDCALL getSumLateralWaterFlow(long n); - __EXTERN double DLL_EXPORT __STDCALL getSumLateralWaterFlowIn(long n); - __EXTERN double DLL_EXPORT __STDCALL getSumLateralWaterFlowOut(long n); + __EXTERN double DLL_EXPORT __STDCALL getWaterConductivity(long nodeIndex); + __EXTERN double DLL_EXPORT __STDCALL getWaterFlow(long nodeIndex, short direction); + __EXTERN double DLL_EXPORT __STDCALL getSumLateralWaterFlow(long nodeIndex); + __EXTERN double DLL_EXPORT __STDCALL getSumLateralWaterFlowIn(long nodeIndex); + __EXTERN double DLL_EXPORT __STDCALL getSumLateralWaterFlowOut(long nodeIndex); __EXTERN double DLL_EXPORT __STDCALL getWaterStorage(); + __EXTERN float DLL_EXPORT __STDCALL getPond(long nodeIndex); // HEAT __EXTERN int DLL_EXPORT __STDCALL setHeatSinkSource(long nodeIndex, double myHeatFlow); diff --git a/agrolib/soilFluxes3D/header/solver.h b/agrolib/soilFluxes3D/header/solver.h index ba8739c2..52195724 100644 --- a/agrolib/soilFluxes3D/header/solver.h +++ b/agrolib/soilFluxes3D/header/solver.h @@ -1,7 +1,7 @@ #ifndef SOLVER_H #define SOLVER_H - inline double square(double x) {return ((x)*(x));} + inline double square(double x) { return ((x)*(x)); } double distance(unsigned long index1, unsigned long index2); diff --git a/agrolib/soilFluxes3D/header/types.h b/agrolib/soilFluxes3D/header/types.h index ee72271b..1d4bfaf5 100644 --- a/agrolib/soilFluxes3D/header/types.h +++ b/agrolib/soilFluxes3D/header/types.h @@ -8,6 +8,8 @@ #include "extra.h" #endif + #include "commonConstants.h" + struct Tboundary { short type; @@ -53,9 +55,9 @@ struct TlinkedNode { - long index; /*!< index of linked elements */ - float area; /*!< interface area [m^2] */ - float sumFlow; /*!< [m^3] sum of flow(i,j) */ + long index; /*!< index of linked elements */ + float area; /*!< interface area [m^2] */ + float sumFlow; /*!< [m3] sum of flow(i,j) */ TCrit3DLinkedNodeExtra* linkedExtra; /*!< extra variables for heat flux */ }; @@ -63,18 +65,17 @@ struct Tsoil { - double VG_alpha; /*!< [m^-1] Van Genutchen alpha parameter */ + double VG_alpha; /*!< [m-1] Van Genutchen alpha parameter */ double VG_n; /*!< [-] Van Genutchen n parameter */ double VG_m; /*!< [-] Van Genutchen m parameter ]0. , 1.[ */ double VG_he; /*!< [m] air-entry potential for modified VG formulation */ double VG_Sc; /*!< [-] reduction factor for modified VG formulation */ - double Theta_s; /*!< [m^3/m^3] saturated water content */ - double Theta_r; /*!< [m^3/m^3] residual water content */ - double K_sat; /*!< [m/sec] saturated hydraulic conductivity */ + double Theta_s; /*!< [m3 m-3] saturated water content */ + double Theta_r; /*!< [m3 m-3] residual water content */ + double K_sat; /*!< [m sec-1] saturated hydraulic conductivity */ double Mualem_L; /*!< [-] Mualem tortuosity parameter */ - double Roughness; /*!< [s/m^0.33] surface: Manning roughness */ - double Pond; /*!< [m] surface: height of immobilized water */ + double Roughness; /*!< [s m-1/3] surface: Manning roughness */ //for heat double organicMatter; /*!< [-] fraction of organic matter */ @@ -85,18 +86,20 @@ struct TCrit3Dnode { double Se; /*!< [-] degree of saturation */ - double k; /*!< [m s^-1] soil water conductivity */ + double k; /*!< [m s-1] soil water conductivity */ double H; /*!< [m] pressure head */ double oldH; /*!< [m] previous pressure head */ double bestH; /*!< [m] pressure head of best iteration */ - double waterSinkSource; /*!< [m^3 s^-1] water sink source */ - double Qw; /*!< [m^3 s^-1] water flow */ + double waterSinkSource; /*!< [m3 s-1] water sink source */ + double Qw; /*!< [m3 s-1] water flow */ - double volume_area; /*!< [m^3] sub-surface: volume of voxel */ - /*!< [m^2] surface: area of voxel */ + double volume_area; /*!< [m3] sub-surface: volume of voxel */ + /*!< [m2] surface: area of voxel */ float x, y; /*!< [m] coordinates of the center of the voxel */ double z; /*!< [m] heigth of the center of the voxel */ + float pond; /*!< [m] only surface: height of immobilized water */ + Tsoil *Soil; /*!< soil pointer */ Tboundary *boundary; /*!< boundary pointer */ TlinkedNode up; /*!< upper link */ @@ -133,7 +136,7 @@ long index = NOLINK; double width; /*!< [m] */ double height; /*!< [m] */ - double roughness; /*!< [s m-1/3] */ + double roughness; /*!< [s m-1/3] Manning roughness */ double slope; /*!< [-] */ }; diff --git a/agrolib/soilFluxes3D/soilFluxes3D.cpp b/agrolib/soilFluxes3D/soilFluxes3D.cpp index 402fa5f0..a46aa653 100644 --- a/agrolib/soilFluxes3D/soilFluxes3D.cpp +++ b/agrolib/soilFluxes3D/soilFluxes3D.cpp @@ -182,22 +182,23 @@ int DLL_EXPORT __STDCALL setNumericalParameters(float minDeltaT, float maxDeltaT * k_lateral_vertical_ratio = 10 * \param waterRetentionCurve * \param conductivityMeanType - * \param horizVertRatioConductivity + * \param conductivityHorizVertRatio * \return OK or PARAMETER_ERROR */ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, - int conductivityMeanType, float horizVertRatioConductivity) + int conductivityMeanType, float conductivityHorizVertRatio) { myParameters.waterRetentionCurve = waterRetentionCurve; myParameters.meanType = conductivityMeanType; - if ((horizVertRatioConductivity >= 0.1) && (horizVertRatioConductivity <= 100)) + if ((conductivityHorizVertRatio >= 0.1) && (conductivityHorizVertRatio <= 100)) { - myParameters.k_lateral_vertical_ratio = horizVertRatioConductivity; + myParameters.k_lateral_vertical_ratio = conductivityHorizVertRatio; return CRIT3D_OK; } else { + // default myParameters.k_lateral_vertical_ratio = 10.; return PARAMETER_ERROR; } @@ -240,6 +241,14 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, nodeListPtr[myIndex].volume_area = volume_or_area; /*!< area on surface elements, volume on sub-surface */ nodeListPtr[myIndex].isSurface = isSurface; + if (isSurface) + { + nodeListPtr[myIndex].pond = 0.0001f; // [m] + } + else + { + nodeListPtr[myIndex].pond = NODATA; + } nodeListPtr[myIndex].waterSinkSource = 0.; @@ -343,7 +352,26 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, nodeListPtr[nodeIndex].Soil = &Surface_List[surfaceIndex]; - return(CRIT3D_OK); + return CRIT3D_OK; + } + + + /*! + * \brief setNodePond + * \param nodeIndex + * \param pond [m] + * \return OK/ERROR + */ + int DLL_EXPORT __STDCALL setNodePond(long nodeIndex, float pond) + { + if (nodeListPtr == nullptr) + return MEMORY_ERROR; + if (nodeIndex < 0 || (! nodeListPtr[nodeIndex].isSurface)) + return INDEX_ERROR; + + nodeListPtr[nodeIndex].pond = pond; + + return CRIT3D_OK; } @@ -416,16 +444,15 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, } - int DLL_EXPORT __STDCALL setSurfaceProperties(int surfaceIndex, double roughness, double surfacePond) + int DLL_EXPORT __STDCALL setSurfaceProperties(int surfaceIndex, double roughness) { - if (roughness < 0 || surfacePond < 0) + if (roughness < 0) return PARAMETER_ERROR; if (surfaceIndex > int(Surface_List.size()-1)) Surface_List.resize(surfaceIndex+1); Surface_List[surfaceIndex].Roughness = roughness; - Surface_List[surfaceIndex].Pond = surfacePond; return CRIT3D_OK; } @@ -434,17 +461,17 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief setMatricPotential * \param nodeIndex - * \param potential [m] + * \param psi [m] * \return OK/ERROR */ - int DLL_EXPORT __STDCALL setMatricPotential(long nodeIndex, double potential) + int DLL_EXPORT __STDCALL setMatricPotential(long nodeIndex, double psi) { if (nodeListPtr == nullptr) return MEMORY_ERROR; if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) return INDEX_ERROR; - nodeListPtr[nodeIndex].H = potential + nodeListPtr[nodeIndex].z; + nodeListPtr[nodeIndex].H = psi + nodeListPtr[nodeIndex].z; nodeListPtr[nodeIndex].oldH = nodeListPtr[nodeIndex].H; if (nodeListPtr[nodeIndex].isSurface) @@ -498,7 +525,7 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief setWaterContent * \param nodeIndex - * \param waterContent [m^3 m^-3] + * \param waterContent [m] surface - [m3 m-3] sub-surface * \return OK/ERROR */ int DLL_EXPORT __STDCALL setWaterContent(long nodeIndex, double waterContent) @@ -530,6 +557,31 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, } + /*! + * \brief setDegreeOfSaturation + * \param nodeIndex + * \param degreeOfSaturation [-] (only sub-surface) + * \return OK/ERROR + */ + int DLL_EXPORT __STDCALL setDegreeOfSaturation(long nodeIndex, double degreeOfSaturation) + { + if (nodeListPtr == nullptr) return MEMORY_ERROR; + + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) return INDEX_ERROR; + + if (nodeListPtr[nodeIndex].isSurface) return INDEX_ERROR; + + if ((degreeOfSaturation < 0.) || (degreeOfSaturation > 1.)) return PARAMETER_ERROR; + + nodeListPtr[nodeIndex].Se = degreeOfSaturation; + nodeListPtr[nodeIndex].H = nodeListPtr[nodeIndex].z - psi_from_Se(nodeIndex); + nodeListPtr[nodeIndex].oldH = nodeListPtr[nodeIndex].H; + nodeListPtr[nodeIndex].k = computeK(nodeIndex); + + return CRIT3D_OK; + } + + /*! * \brief setWaterSinkSource * \param nodeIndex @@ -566,6 +618,25 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, } + /*! + * \brief getPond + * \param nodeIndex + * \return surface maximum pond [m] + */ + float DLL_EXPORT __STDCALL getPond(long nodeIndex) + { + if (nodeListPtr == nullptr) + return MEMORY_ERROR; + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) + return INDEX_ERROR; + + if (! nodeListPtr[nodeIndex].isSurface) + return INDEX_ERROR; + + return nodeListPtr[nodeIndex].pond; + } + + /*! * \brief getWaterContent * \param nodeIndex @@ -657,7 +728,7 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief getTotalWaterContent - * \return total water content [m^3] + * \return total water content [m3] */ double DLL_EXPORT __STDCALL getTotalWaterContent() { @@ -702,7 +773,7 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, double DLL_EXPORT __STDCALL getTotalPotential(long nodeIndex) { if (nodeListPtr == nullptr) return(MEMORY_ERROR); - if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) return(INDEX_ERROR); + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) return(INDEX_ERROR); return (nodeListPtr[nodeIndex].H); } @@ -710,22 +781,22 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief getWaterFlow - * \param n + * \param nodeIndex * \param direction * \return maximum integrated flow in the requested direction [m^3] */ - double DLL_EXPORT __STDCALL getWaterFlow(long n, short direction) + double DLL_EXPORT __STDCALL getWaterFlow(long nodeIndex, short direction) { if (nodeListPtr == nullptr) return MEMORY_ERROR; - if ((n < 0) || (n >= myStructure.nrNodes)) return INDEX_ERROR; + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) return INDEX_ERROR; double maxFlow = 0.0; switch (direction) { case UP: - if (nodeListPtr[n].up.index != NOLINK) + if (nodeListPtr[nodeIndex].up.index != NOLINK) { - return nodeListPtr[n].up.sumFlow; + return nodeListPtr[nodeIndex].up.sumFlow; } else { @@ -733,9 +804,9 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, } case DOWN: - if (nodeListPtr[n].down.index != NOLINK) + if (nodeListPtr[nodeIndex].down.index != NOLINK) { - return nodeListPtr[n].down.sumFlow; + return nodeListPtr[nodeIndex].down.sumFlow; } else { @@ -745,10 +816,10 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, case LATERAL: // return maximum lateral flow for (short i = 0; i < myStructure.nrLateralLinks; i++) - if (nodeListPtr[n].lateral[i].index != NOLINK) - if (fabs(nodeListPtr[n].lateral[i].sumFlow) > maxFlow) + if (nodeListPtr[nodeIndex].lateral[i].index != NOLINK) + if (fabs(nodeListPtr[nodeIndex].lateral[i].sumFlow) > maxFlow) { - maxFlow = nodeListPtr[n].lateral[i].sumFlow; + maxFlow = nodeListPtr[nodeIndex].lateral[i].sumFlow; } return maxFlow; @@ -761,19 +832,19 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief getSumLateralWaterFlow - * \param n + * \param nodeIndex * \return integrated lateral flow over the time step [m^3] */ - double DLL_EXPORT __STDCALL getSumLateralWaterFlow(long n) + double DLL_EXPORT __STDCALL getSumLateralWaterFlow(long nodeIndex) { if (nodeListPtr == nullptr) return MEMORY_ERROR; - if ((n < 0) || (n >= myStructure.nrNodes)) return INDEX_ERROR; + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) return INDEX_ERROR; double sumLateralFlow = 0.0; for (short i = 0; i < myStructure.nrLateralLinks; i++) { - if (nodeListPtr[n].lateral[i].index != NOLINK) - sumLateralFlow += nodeListPtr[n].lateral[i].sumFlow; + if (nodeListPtr[nodeIndex].lateral[i].index != NOLINK) + sumLateralFlow += nodeListPtr[nodeIndex].lateral[i].sumFlow; } return sumLateralFlow; } @@ -781,19 +852,21 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief getSumLateralWaterFlowIn - * \param n + * \param nodeIndex * \return integrated lateral inflow over the time step [m^3] */ - double DLL_EXPORT __STDCALL getSumLateralWaterFlowIn(long n) + double DLL_EXPORT __STDCALL getSumLateralWaterFlowIn(long nodeIndex) { - if (nodeListPtr == nullptr) return MEMORY_ERROR; - if ((n < 0) || (n >= myStructure.nrNodes)) return INDEX_ERROR; + if (nodeListPtr == nullptr) + return MEMORY_ERROR; + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) + return INDEX_ERROR; double sumLateralFlow = 0.0; for (short i = 0; i < myStructure.nrLateralLinks; i++) - if (nodeListPtr[n].lateral[i].index != NOLINK) - if (nodeListPtr[n].lateral[i].sumFlow > 0) - sumLateralFlow += nodeListPtr[n].lateral[i].sumFlow; + if (nodeListPtr[nodeIndex].lateral[i].index != NOLINK) + if (nodeListPtr[nodeIndex].lateral[i].sumFlow > 0) + sumLateralFlow += nodeListPtr[nodeIndex].lateral[i].sumFlow; return sumLateralFlow; } @@ -801,19 +874,21 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, /*! * \brief getSumLateralWaterFlowOut - * \param n + * \param nodeIndex * \return integrated lateral outflow over the time step [m^3] */ - double DLL_EXPORT __STDCALL getSumLateralWaterFlowOut(long n) + double DLL_EXPORT __STDCALL getSumLateralWaterFlowOut(long nodeIndex) { - if (nodeListPtr == nullptr) return MEMORY_ERROR; - if ((n < 0) || (n >= myStructure.nrNodes)) return INDEX_ERROR; + if (nodeListPtr == nullptr) + return MEMORY_ERROR; + if ((nodeIndex < 0) || (nodeIndex >= myStructure.nrNodes)) + return INDEX_ERROR; double sumLateralFlow = 0.0; for (short i = 0; i < myStructure.nrLateralLinks; i++) - if (nodeListPtr[n].lateral[i].index != NOLINK) - if (nodeListPtr[n].lateral[i].sumFlow < 0) - sumLateralFlow += nodeListPtr[n].lateral[i].sumFlow; + if (nodeListPtr[nodeIndex].lateral[i].index != NOLINK) + if (nodeListPtr[nodeIndex].lateral[i].sumFlow < 0) + sumLateralFlow += nodeListPtr[nodeIndex].lateral[i].sumFlow; return sumLateralFlow; } @@ -822,10 +897,15 @@ int DLL_EXPORT __STDCALL setHydraulicProperties(int waterRetentionCurve, void DLL_EXPORT __STDCALL initializeBalance() { InitializeBalanceWater(); + if (myStructure.computeHeat) + { initializeBalanceHeat(); + } else + { balanceWholePeriod.heatMBR = 1.; + } } diff --git a/agrolib/soilFluxes3D/water.cpp b/agrolib/soilFluxes3D/water.cpp index f418f611..15a7890a 100644 --- a/agrolib/soilFluxes3D/water.cpp +++ b/agrolib/soilFluxes3D/water.cpp @@ -94,9 +94,8 @@ double runoff(long i, long j, TlinkedNode *link, double deltaT, unsigned long ap */ } - double H = MAXVALUE(Hi, Hj); - double z = MAXVALUE(nodeListPtr[i].z + nodeListPtr[i].Soil->Pond, nodeListPtr[j].z + nodeListPtr[j].Soil->Pond); + double z = MAXVALUE(nodeListPtr[i].z + nodeListPtr[i].pond, nodeListPtr[j].z + nodeListPtr[j].pond); double Hs = H - z; if (Hs <= 0.) return(0.); @@ -323,7 +322,7 @@ bool waterFlowComputation(double deltaT) isValidStep = waterBalance(deltaT, approximationNr); if (getForcedHalvedTime()) return (false); } - while ((!isValidStep) && (++approximationNr < myParameters.maxApproximationsNumber)); + while ((! isValidStep) && (++approximationNr < myParameters.maxApproximationsNumber)); return isValidStep; } @@ -368,7 +367,7 @@ bool computeWater(double maxTime, double *acceptedTime) isStepOK = waterFlowComputation(*acceptedTime); - if (!isStepOK) restoreWater(); + if (! isStepOK) restoreWater(); } return (isStepOK); } diff --git a/agrolib/soilWidget/soilTable.cpp b/agrolib/soilWidget/soilTable.cpp index fc5ab086..711a7bf6 100644 --- a/agrolib/soilWidget/soilTable.cpp +++ b/agrolib/soilWidget/soilTable.cpp @@ -18,23 +18,22 @@ Crit3DSoilTable::Crit3DSoilTable(tableType type) : type(type) QList tableHeader; if (type == dbTable) { - this->setColumnCount(10); - tableHeader << "Upper depth [cm]" << "Lower depth [cm]" << "Sand [%]" << "Silt [%]" << "Clay [%]" << "Coarse [%]" << "O.M. [%]" - << "B.D. [g/cm3]" << "K Sat [cm/d]" << "Theta S [-]"; + this->setColumnCount(12); + tableHeader << "Upper depth [cm]" << "Lower depth [cm]" << "Sand [%]" << "Silt [%]" << "Clay [%]" << "Coarse [%]" << "O.M. [%]" + << "B.D. [g/cm3]" << "K Sat [cm/d]" << "Theta S [-]" << "c' [kPa]" << "Φ' [°]"; } else if (type == modelTable) { - this->setColumnCount(11); + this->setColumnCount(13); tableHeader << "USDA Texture" << "Coarse [%]" << "O.M. [%]" << "B.D. [g/cm3]" << "K Sat [cm/d]" << "ThetaS [-]" << "ThetaR [-]" << "Air entry [KPa]" - << "alpha [KPa^-1]" << " n [-] " << " m [-] "; + << "α [KPa^-1]" << " n [-] " << " m [-] " << "c' [kPa]" << "Φ' [°]"; } this->setHorizontalHeaderLabels(tableHeader); this->resizeColumnsToContents(); this->setSelectionMode(QAbstractItemView::SingleSelection); this->setShowGrid(true); - //this->setStyleSheet("QTableView {selection-background-color: green;}"); this->setStyleSheet("QTableView::item:selected { color:black; border: 3px solid black}"); if (type == dbTable) @@ -45,6 +44,103 @@ Crit3DSoilTable::Crit3DSoilTable(tableType type) : type(type) { this->setEditTriggers(QAbstractItemView::NoEditTriggers); } + + if (type == dbTable) + { + QTableWidgetItem *currentHeaderItem = horizontalHeaderItem(2); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of sand (from 2.0 to 0.05 mm)"); + + currentHeaderItem = horizontalHeaderItem(3); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of silt (from 0.05 to 0.002 mm)"); + + currentHeaderItem = this->horizontalHeaderItem(4); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of clay (minor than 0.002 mm)"); + + currentHeaderItem = this->horizontalHeaderItem(5); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of coarse fragments (major than 2.0 mm)"); + + currentHeaderItem = this->horizontalHeaderItem(6); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of organic matter"); + + currentHeaderItem = this->horizontalHeaderItem(7); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Bulk density"); + + currentHeaderItem = this->horizontalHeaderItem(8); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Saturated hydraulic conductivity"); + + currentHeaderItem = this->horizontalHeaderItem(9); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Water content at saturation (SAT)"); + + currentHeaderItem = this->horizontalHeaderItem(10); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Soil effective cohesion"); + + currentHeaderItem = this->horizontalHeaderItem(11); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Soil friction angle"); + } + else if (type == modelTable) + { + QTableWidgetItem *currentHeaderItem = horizontalHeaderItem(0); + if (currentHeaderItem) + currentHeaderItem->setToolTip("USDA textural soil classification"); + + currentHeaderItem = horizontalHeaderItem(1); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of coarse fragments (major than 2.0 mm)"); + + currentHeaderItem = this->horizontalHeaderItem(2); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Percentage of organic matter"); + + currentHeaderItem = this->horizontalHeaderItem(3); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Bulk density"); + + currentHeaderItem = this->horizontalHeaderItem(4); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Saturated hydraulic conductivity"); + + currentHeaderItem = this->horizontalHeaderItem(5); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Water content at saturation (SAT)"); + + currentHeaderItem = this->horizontalHeaderItem(6); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Water content at wilting point (WP)"); + + currentHeaderItem = this->horizontalHeaderItem(7); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Air entry value"); + + currentHeaderItem = this->horizontalHeaderItem(8); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Van Genuchten parameter α"); + + currentHeaderItem = this->horizontalHeaderItem(9); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Van Genuchten parameter n"); + + currentHeaderItem = this->horizontalHeaderItem(10); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Van Genuchten parameter m"); + + currentHeaderItem = this->horizontalHeaderItem(11); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Soil effective cohesion"); + + currentHeaderItem = this->horizontalHeaderItem(12); + if (currentHeaderItem) + currentHeaderItem->setToolTip("Soil friction angle"); + } } @@ -52,7 +148,8 @@ void Crit3DSoilTable::mouseMoveEvent(QMouseEvent *event) { QPoint pos = event->pos(); QTableWidgetItem *item = this->itemAt(pos); - if(!item) return; + if(! item) + return; if (item->background().color() == Qt::red) { @@ -62,7 +159,7 @@ void Crit3DSoilTable::mouseMoveEvent(QMouseEvent *event) } else if (type == modelTable) { - QToolTip::showText(this->viewport()->mapToGlobal(pos), "wrong horizon", this, QRect(pos,QSize(100,100)), 800); + QToolTip::showText(this->viewport()->mapToGlobal(pos), "wrong horizon or missing db", this, QRect(pos,QSize(100,100)), 800); } } else if(item->background().color() == Qt::yellow) diff --git a/agrolib/soilWidget/soilWidget.cpp b/agrolib/soilWidget/soilWidget.cpp index f6af3ab0..be2d0735 100644 --- a/agrolib/soilWidget/soilWidget.cpp +++ b/agrolib/soilWidget/soilWidget.cpp @@ -1,5 +1,5 @@ /*! - CRITERIA3D + soilWidget.cpp \copyright 2016 Fausto Tomei, Gabriele Antolini, Laura Costantini Alberto Pistocchi, Marco Bittelli, Antonio Volta @@ -55,7 +55,7 @@ Crit3DSoilWidget::Crit3DSoilWidget() geotechnicsClassList.resize(19); this->setWindowTitle(QStringLiteral("CRITERIA - Soil Editor")); - this->resize(1240, 700); + this->resize(1400, 700); // layout QVBoxLayout *mainLayout = new QVBoxLayout(); @@ -286,12 +286,15 @@ void Crit3DSoilWidget::setDbSoil(QSqlDatabase dbOpened, QString soilCode) // load default VG parameters if (! loadVanGenuchtenParameters(dbSoil, textureClassList, errorStr)) { - QMessageBox::critical(nullptr, "Error", "loadVanGenuchtenParameters: " + errorStr); + QMessageBox::critical(nullptr, "Error", "loadVanGenuchtenParameters\n" + errorStr); return; } // load default geotechnics parameters (not mandatory) - loadGeotechnicsParameters(dbSoil, geotechnicsClassList, errorStr); + if (! loadGeotechnicsParameters(dbSoil, geotechnicsClassList, errorStr)) + { + QMessageBox::warning(nullptr, "Warning", "Failed to load geotecnical parameters for slope stability: missing reference db"); + } // read soil list QList soilStringList; diff --git a/agrolib/soilWidget/soilWidget.pro b/agrolib/soilWidget/soilWidget.pro index 6b695bf1..497dd600 100644 --- a/agrolib/soilWidget/soilWidget.pro +++ b/agrolib/soilWidget/soilWidget.pro @@ -3,7 +3,6 @@ # Soil Widget library # This project is part of CRITERIA-3D distribution # -# #---------------------------------------------------- QT += widgets sql charts diff --git a/agrolib/soilWidget/tabHorizons.cpp b/agrolib/soilWidget/tabHorizons.cpp index b5eeab52..eed115fa 100644 --- a/agrolib/soilWidget/tabHorizons.cpp +++ b/agrolib/soilWidget/tabHorizons.cpp @@ -111,6 +111,10 @@ void TabHorizons::insertSoilHorizons(soil::Crit3DSoil *soil, std::vectoritem(i,8)->setTextAlignment(Qt::AlignRight); tableDb->setItem(i, 9, new QTableWidgetItem( QString::number(mySoil->horizon[i].dbData.thetaSat, 'f', 3))); tableDb->item(i,9)->setTextAlignment(Qt::AlignRight); + tableDb->setItem(i, 10, new QTableWidgetItem( QString::number(mySoil->horizon[i].dbData.effectiveCohesion, 'f', 0))); + tableDb->item(i,10)->setTextAlignment(Qt::AlignRight); + tableDb->setItem(i, 11, new QTableWidgetItem( QString::number(mySoil->horizon[i].dbData.frictionAngle, 'f', 0))); + tableDb->item(i,11)->setTextAlignment(Qt::AlignRight); tableModel->setItem(i, 0, new QTableWidgetItem( QString::fromStdString(mySoil->horizon[i].texture.classNameUSDA))); if (mySoil->horizon[i].coarseFragments != NODATA) @@ -149,6 +153,10 @@ void TabHorizons::insertSoilHorizons(soil::Crit3DSoil *soil, std::vectoritem(i,9)->setTextAlignment(Qt::AlignRight); tableModel->setItem(i, 10, new QTableWidgetItem( QString::number(mySoil->horizon[i].vanGenuchten.m, 'f', 3 ))); tableModel->item(i,10)->setTextAlignment(Qt::AlignRight); + tableModel->setItem(i, 11, new QTableWidgetItem( QString::number(mySoil->horizon[i].effectiveCohesion, 'f', 0 ))); + tableModel->item(i,11)->setTextAlignment(Qt::AlignRight); + tableModel->setItem(i, 12, new QTableWidgetItem( QString::number(mySoil->horizon[i].frictionAngle, 'f', 0 ))); + tableModel->item(i,12)->setTextAlignment(Qt::AlignRight); } // check all Depths @@ -237,6 +245,10 @@ void TabHorizons::updateTableModel(soil::Crit3DSoil *soil) tableModel->item(i,9)->setTextAlignment(Qt::AlignRight); tableModel->setItem(i, 10, new QTableWidgetItem( QString::number(mySoil->horizon[i].vanGenuchten.m, 'f', 3 ))); tableModel->item(i,10)->setTextAlignment(Qt::AlignRight); + tableModel->setItem(i, 11, new QTableWidgetItem( QString::number(mySoil->horizon[i].effectiveCohesion, 'f', 0 ))); + tableModel->item(i,11)->setTextAlignment(Qt::AlignRight); + tableModel->setItem(i, 12, new QTableWidgetItem( QString::number(mySoil->horizon[i].frictionAngle, 'f', 0 ))); + tableModel->item(i,12)->setTextAlignment(Qt::AlignRight); } // check other values @@ -263,7 +275,7 @@ bool TabHorizons::checkDepths() for (int horizonNum = 0; horizonNumrowCount(); horizonNum++) { //except first row - if ( horizonNum > 0) + if (horizonNum > 0) { if (mySoil->horizon[unsigned(horizonNum)].dbData.upperDepth != mySoil->horizon[horizonNum-1].dbData.lowerDepth) { @@ -334,7 +346,7 @@ bool TabHorizons::checkHorizonData(int horizonNum) tableDb->item(horizonNum,5)->setBackground(Qt::red); } - if (dbData->organicMatter != NODATA && (dbData->organicMatter < 0 || dbData->organicMatter > 100)) + if ( dbData->organicMatter != NODATA && ((dbData->organicMatter < 0) || (dbData->organicMatter > 100)) ) { tableDb->item(horizonNum,6)->setBackground(Qt::red); } @@ -354,6 +366,17 @@ bool TabHorizons::checkHorizonData(int horizonNum) tableDb->item(horizonNum,9)->setBackground(Qt::red); } + if (dbData->effectiveCohesion != NODATA && (dbData->effectiveCohesion < 0 || dbData->effectiveCohesion > 110)) + { + tableDb->item(horizonNum,10)->setBackground(Qt::red); + } + + if (dbData->frictionAngle != NODATA && (dbData->frictionAngle < 0 || dbData->frictionAngle > 50)) + { + tableDb->item(horizonNum,11)->setBackground(Qt::red); + } + + return goOn; } @@ -372,6 +395,8 @@ void TabHorizons::setInvalidTableModelRow(int horizonNum) tableModel->item(horizonNum,8)->setBackground(Qt::red); tableModel->item(horizonNum,9)->setBackground(Qt::red); tableModel->item(horizonNum,10)->setBackground(Qt::red); + tableModel->item(horizonNum,11)->setBackground(Qt::red); + tableModel->item(horizonNum,12)->setBackground(Qt::red); } @@ -436,6 +461,17 @@ void TabHorizons::checkComputedValues(int horizonNum) { tableModel->item(horizonNum,5)->setBackground(Qt::yellow); } + + if (abs(horizon->dbData.effectiveCohesion - horizon->effectiveCohesion) > EPSILON) + { + tableModel->item(horizonNum,11)->setBackground(Qt::yellow); + } + + if (abs(horizon->dbData.frictionAngle - horizon->frictionAngle) > EPSILON) + { + tableModel->item(horizonNum,12)->setBackground(Qt::yellow); + } + } @@ -703,6 +739,34 @@ void TabHorizons::cellChanged(int row, int column) } break; } + case 10: + { + if (data == QString::number(NODATA) || data.isEmpty()) + { + mySoil->horizon[unsigned(row)].dbData.effectiveCohesion = NODATA; + tableDb->item(row, column)->setText(""); + } + else + { + mySoil->horizon[unsigned(row)].dbData.effectiveCohesion = data.toDouble(); + tableDb->item(row, column)->setText(QString::number(data.toDouble(), 'f', 0)); + } + break; + } + case 11: + { + if (data == QString::number(NODATA) || data.isEmpty()) + { + mySoil->horizon[unsigned(row)].dbData.frictionAngle = NODATA; + tableDb->item(row, column)->setText(""); + } + else + { + mySoil->horizon[unsigned(row)].dbData.frictionAngle = data.toDouble(); + tableDb->item(row, column)->setText(QString::number(data.toDouble(), 'f', 0)); + } + break; + } } std::string errorString; @@ -737,6 +801,9 @@ void TabHorizons::cellChanged(int row, int column) tableModel->item(row,8)->setText(QString::number(mySoil->horizon[unsigned(row)].vanGenuchten.alpha, 'f', 3)); tableModel->item(row,9)->setText(QString::number(mySoil->horizon[unsigned(row)].vanGenuchten.n, 'f', 3)); tableModel->item(row,10)->setText(QString::number(mySoil->horizon[unsigned(row)].vanGenuchten.m, 'f', 3)); + tableModel->item(row,11)->setText(QString::number(mySoil->horizon[unsigned(row)].effectiveCohesion, 'f', 0)); + tableModel->item(row,12)->setText(QString::number(mySoil->horizon[unsigned(row)].frictionAngle, 'f', 0)); + // reset background color for the row changed for (int j = 0; j < tableDb->columnCount(); j++) @@ -843,6 +910,8 @@ void TabHorizons::addRowClicked() newHorizon->dbData.bulkDensity = NODATA; newHorizon->dbData.thetaSat = NODATA; newHorizon->dbData.kSat = NODATA; + newHorizon->dbData.effectiveCohesion = NODATA; + newHorizon->dbData.frictionAngle = NODATA; mySoil->addHorizon(numRow, *newHorizon); // check all Depths diff --git a/agrolib/synchronicityWidget/interpolationChartView.cpp b/agrolib/synchronicityWidget/interpolationChartView.cpp index 5b7645b7..558992d4 100644 --- a/agrolib/synchronicityWidget/interpolationChartView.cpp +++ b/agrolib/synchronicityWidget/interpolationChartView.cpp @@ -78,7 +78,7 @@ void InterpolationChartView::drawGraphInterpolation(std::vector values, Q axisX->setRange(QDateTime(myStartDate, QTime(1,0,0),Qt::UTC), QDateTime(myStartDate.addDays(values.size()-1), QTime(1,0,0),Qt::UTC)); if ( values.size() <= 10) { - axisX->setTickCount(values.size()); + axisX->setTickCount(int(values.size())); } else { diff --git a/agrolib/synchronicityWidget/synchronicityWidget.cpp b/agrolib/synchronicityWidget/synchronicityWidget.cpp index 878e1095..663ed37f 100644 --- a/agrolib/synchronicityWidget/synchronicityWidget.cpp +++ b/agrolib/synchronicityWidget/synchronicityWidget.cpp @@ -191,7 +191,7 @@ void Crit3DSynchronicityWidget::addStationGraph() if ((float)myX.size() / days * 100.0 > minPerc) { - statistics::linearRegression(myX, myY, myX.size(), false, &y_intercept, &trend, &r2); + statistics::linearRegression(myX, myY, int(myX.size()), false, &y_intercept, &trend, &r2); } else { @@ -398,7 +398,7 @@ void Crit3DSynchronicityWidget::changeInterpolationDate() void Crit3DSynchronicityWidget::on_actionChangeLeftSynchAxis() { - DialogChangeAxis changeAxisDialog(true); + DialogChangeAxis changeAxisDialog(1, false); if (changeAxisDialog.result() == QDialog::Accepted) { synchronicityChartView->setYmax(changeAxisDialog.getMaxVal()); @@ -408,7 +408,7 @@ void Crit3DSynchronicityWidget::on_actionChangeLeftSynchAxis() void Crit3DSynchronicityWidget::on_actionChangeLeftInterpolationAxis() { - DialogChangeAxis changeAxisDialog(true); + DialogChangeAxis changeAxisDialog(1, false); if (changeAxisDialog.result() == QDialog::Accepted) { interpolationChartView->setYmax(changeAxisDialog.getMaxVal()); diff --git a/agrolib/utilities/utilities.cpp b/agrolib/utilities/utilities.cpp index 426322af..ea945b74 100644 --- a/agrolib/utilities/utilities.cpp +++ b/agrolib/utilities/utilities.cpp @@ -672,12 +672,12 @@ bool writeJson(const QString & ancestor, const std::vector &fieldNames bool isFloat = false; - for (int i=0; i < values.size(); i++) + for (int i=0; i < int(values.size()); i++) { if (values[i].size() != fieldNames.size() || values[i].size() != dataType.size()) return false; recordObject.empty(); - for (int j=0; j < values[i].size(); j++) + for (int j=0; j < int(values[i].size()); j++) { if (dataType[j] == "float") recordObject.insert(fieldNames[j], values[i][j].toFloat(&isFloat)); diff --git a/agrolib/waterTable/dialogSummary.cpp b/agrolib/waterTable/dialogSummary.cpp index f670d21e..7e73cf13 100644 --- a/agrolib/waterTable/dialogSummary.cpp +++ b/agrolib/waterTable/dialogSummary.cpp @@ -38,10 +38,6 @@ DialogSummary::DialogSummary(WaterTable myWaterTable) QLineEdit* myRMSE = new QLineEdit(QString::number(myWaterTable.getRMSE(),'f', 2)); myRMSE->setReadOnly(true); - QLabel* labelNASH = new QLabel("Nash-Sutcliffe [-]: "); - QLineEdit* myNASH = new QLineEdit(QString::number(myWaterTable.getNASH(),'f', 2)); - myNASH->setReadOnly(true); - QLabel* labelEfIndex = new QLabel("Efficiency Index [-]: "); QLineEdit* myEfIndex = new QLineEdit(QString::number(myWaterTable.getEF(),'f', 2)); myEfIndex->setReadOnly(true); @@ -67,9 +63,6 @@ DialogSummary::DialogSummary(WaterTable myWaterTable) infoLayout->addWidget(labelRMSE,6,0,1,1); infoLayout->addWidget(myRMSE,6,1,1,1); - infoLayout->addWidget(labelNASH,7,0,1,1); - infoLayout->addWidget(myNASH,7,1,1,1); - infoLayout->addWidget(labelEfIndex,8,0,1,1); infoLayout->addWidget(myEfIndex,8,1,1,1); diff --git a/agrolib/waterTable/importData.cpp b/agrolib/waterTable/importData.cpp index a70eb0cf..31b242d0 100644 --- a/agrolib/waterTable/importData.cpp +++ b/agrolib/waterTable/importData.cpp @@ -3,97 +3,240 @@ #include #include #include +#include "well.h" +#include "gis.h" -bool loadCsvRegistry(QString csvRegistry, std::vector &wellList, QString &errorStr, int &wrongLines) +bool loadWaterTableLocationCsv(const QString &csvFileName, std::vector &wellList, + const gis::Crit3DGisSettings& gisSettings, QString &errorStr, int &wrongLines) { - errorStr = ""; wellList.clear(); - QFile myFile(csvRegistry); + QFile myFile(csvFileName); + if (! myFile.open(QFile::ReadOnly | QFile::Text) ) + { + errorStr = "Csv file does not exist:\n" + csvFileName; + return false; + } + + QTextStream in(&myFile); + int nrRequiredFields = 3; + + // check header + bool isLatLon = false; + QString line = in.readLine(); + QList headerItems = line.split(","); + if (headerItems.size() != nrRequiredFields) + { + errorStr = "Wrong data! Required ID, utmX, utmY or ID, lat, lon."; + return false; + } + if (headerItems[1].toUpper() == "LAT") + { + isLatLon = true; + } + + errorStr = ""; QList idList; QList errorList; + int validLines = 0; + + while (! in.atEnd()) + { + line = in.readLine(); + QList items = line.split(","); + items.removeAll({}); + if (items.size() < nrRequiredFields) + { + errorList.append(line); + wrongLines++; + continue; + } + + items[0] = items[0].simplified(); + QString id = items[0].remove(QChar('"')); + if (idList.contains(id)) + { + // id already saved + errorList.append(line + "(REPEATED)"); + wrongLines++; + continue; + } + idList.append(id); + + bool isOk; + items[1] = items[1].simplified(); + double value1 = items[1].remove(QChar('"')).toDouble(&isOk); + if (! isOk) + { + errorList.append(line); + wrongLines++; + continue; + } + + items[2] = items[2].simplified(); + double value2 = items[2].remove(QChar('"')).toDouble(&isOk); + if (! isOk) + { + errorList.append(line); + wrongLines++; + continue; + } + + double utmX, utmY, lat, lon; + if (isLatLon) + { + lat = value1; + lon = value2; + gis::getUtmFromLatLon(gisSettings, lat, lon, &utmX, &utmY); + } + else + { + utmX = value1; + utmY = value2; + gis::getLatLonFromUtm(gisSettings, utmX, utmY, &lat, &lon); + } + + Well newWell; + newWell.setId(id); + newWell.setUtmX(utmX); + newWell.setUtmY(utmY); + newWell.setLatitude(lat); + newWell.setLongitude(lon); + wellList.push_back(newWell); + + validLines++; + } + + myFile.close(); + + if (validLines == 0) + { + errorStr = "Wrong wells location:\n" + csvFileName; + return false; + } + + if (wrongLines > 0) + { + errorStr = "ID repeated or with invalid coordinates:\n" + errorList.join("\n"); + } + + return true; +} + + +bool loadWaterTableDepthCsv(const QString &csvFileName, std::vector &wellList, + int waterTableMaximumDepth, QString &errorStr, int &wrongLines) +{ + errorStr = ""; + QFile myFile(csvFileName); + QList errorList; + int posId = 0; - int posUtmx = 1; - int posUtmy = 2; - int nFields = 3; + int posDate = 1; + int posDepth = 2; + + int nrRequiredFields = 3; + int validLines = 0; bool ok; if (! myFile.open(QFile::ReadOnly | QFile::Text) ) { - errorStr = "csvFileName file does not exist"; + errorStr = "Csv file does not exist:\n" + csvFileName; return false; } else { QTextStream in(&myFile); - //skip header + + // check header QString line = in.readLine(); + QList headerItems = line.split(","); + if (headerItems.size() != nrRequiredFields) + { + errorStr = "Wrong data! Required well ID, date, depth."; + return false; + } + while (!in.atEnd()) { line = in.readLine(); QList items = line.split(","); items.removeAll({}); - if (items.size() waterTableMaximumDepth) { - errorList.append(id); + errorList.append(line); wrongLines++; continue; } - Well newWell; - newWell.setId(id); - newWell.setUtmX(utmX); - newWell.setUtmY(utmY); - wellList.push_back(newWell); + + wellList[index].insertData(date, value); + validLines++; } } myFile.close(); + if (validLines == 0) + { + errorStr = "Wrong water table depth:\n" + csvFileName; + return false; + } + if (wrongLines > 0) { - errorStr = "ID repeated or with invalid coordinates: " + errorList.join(","); + errorStr = "ID not existing or with invalid data or value:\n" + errorList.join("\n"); } return true; } -bool loadCsvDepths(QString csvDepths, std::vector &wellList, int waterTableMaximumDepth, QString &errorStr, int &wrongLines) +bool loadCsvDepthsSingleWell(const QString &csvFileName, Well* well, int waterTableMaximumDepth, QString &errorStr, int &wrongLines) { - QFile myFile(csvDepths); + QFile myFile(csvFileName); QList errorList; - int posId = 0; - int posDate = 1; - int posDepth = 2; + int posDate = 0; + int posDepth = 1; - int nFields = 3; + int nFields = 2; bool ok; errorStr = ""; @@ -118,26 +261,6 @@ bool loadCsvDepths(QString csvDepths, std::vector &wellList, int waterTabl wrongLines++; continue; } - items[posId] = items[posId].simplified(); - QString id = items[posId].remove(QChar('"')); - bool found = false; - int index = NODATA; - for (int i = 0; i < wellList.size(); i++) - { - if (wellList[i].getId() == id) - { - found = true; - index = i; - break; - } - } - if (found == false) - { - // id does not exist - errorList.append(line); - wrongLines++; - continue; - } items[posDate] = items[posDate].simplified(); QDate date = QDate::fromString(items[posDate].remove(QChar('"')),"yyyy-MM-dd"); if (! date.isValid()) @@ -155,14 +278,14 @@ bool loadCsvDepths(QString csvDepths, std::vector &wellList, int waterTabl continue; } - wellList[index].insertData(date, value); + well->insertData(date, value); } } myFile.close(); if (wrongLines > 0) { - errorStr = "ID not existing or with invalid data or value:\n" + errorList.join("\n"); + errorStr = "Invalid data or value or data out of range:\n" + errorList.join("\n"); } return true; diff --git a/agrolib/waterTable/importData.h b/agrolib/waterTable/importData.h index e42b085d..497e1702 100644 --- a/agrolib/waterTable/importData.h +++ b/agrolib/waterTable/importData.h @@ -1,13 +1,21 @@ #ifndef IMPORTDATA_H #define IMPORTDATA_H -#include -#ifndef WELL_H - #include "well.h" -#endif + #include + #ifndef WELL_H + #include "well.h" + #endif + #ifndef GIS_H + #include "gis.h" + #endif -bool loadCsvRegistry(QString csvRegistry, std::vector &wellList, QString &errorStr, int &wrongLines); -bool loadCsvDepths(QString csvDepths, std::vector &wellList, int waterTableMaximumDepth, QString &errorStr, int &wrongLines); + bool loadWaterTableLocationCsv(const QString &csvFileName, std::vector &wellList, + const gis::Crit3DGisSettings &gisSettings, QString &errorStr, int &wrongLines); + + bool loadWaterTableDepthCsv(const QString &csvFileName, std::vector &wellList, int waterTableMaximumDepth, + QString &errorStr, int &wrongLines); + + bool loadCsvDepthsSingleWell(const QString &csvFileName, Well* well, int waterTableMaximumDepth, QString &errorStr, int &wrongLines); #endif // IMPORTDATA_H diff --git a/agrolib/waterTable/waterTable.cpp b/agrolib/waterTable/waterTable.cpp index 9fc3730e..c96e1001 100644 --- a/agrolib/waterTable/waterTable.cpp +++ b/agrolib/waterTable/waterTable.cpp @@ -1,101 +1,23 @@ #include "waterTable.h" #include "commonConstants.h" -#include "weatherGenerator.h" +#include "furtherMathFunctions.h" +#include -WaterTable::WaterTable(Crit3DMeteoPoint *linkedMeteoPoint, Crit3DMeteoSettings meteoSettings, gis::Crit3DGisSettings gisSettings) - : linkedMeteoPoint(linkedMeteoPoint), meteoSettings(meteoSettings), gisSettings(gisSettings) -{ - firstMeteoDate = QDate(linkedMeteoPoint->getFirstDailyData().year, linkedMeteoPoint->getFirstDailyData().month, linkedMeteoPoint->getFirstDailyData().day); - lastMeteoDate = QDate(linkedMeteoPoint->getLastDailyData().year, linkedMeteoPoint->getLastDailyData().month, linkedMeteoPoint->getLastDailyData().day); -} - -QString WaterTable::getIdWell() const -{ - return well.getId(); -} - -QDate WaterTable::getFirstDateWell() -{ - firstDateWell = well.getFirstDate(); - return firstDateWell; -} - -QDate WaterTable::getLastDateWell() -{ - lastDateWell = well.getLastDate(); - return lastDateWell; -} - -QMap WaterTable::getObsDepths() -{ - return well.getObsDepths(); -} - -QString WaterTable::getError() const -{ - return error; -} - -float WaterTable::getAlpha() const -{ - return alpha; -} - -float WaterTable::getH0() const -{ - return h0; -} - -int WaterTable::getNrDaysPeriod() const -{ - return nrDaysPeriod; -} - -float WaterTable::getR2() const -{ - return R2; -} - -float WaterTable::getRMSE() const -{ - return RMSE; -} - -float WaterTable::getNASH() const -{ - return NASH; -} - -float WaterTable::getEF() const -{ - return EF; -} - -int WaterTable::getNrObsData() const -{ - return nrObsData; -} - -std::vector WaterTable::getMyDates() const -{ - return myDates; -} -std::vector WaterTable::getMyHindcastSeries() const +WaterTable::WaterTable(std::vector &inputTMin, std::vector &inputTMax, std::vector &inputPrec, + QDate firstMeteoDate, QDate lastMeteoDate, Crit3DMeteoSettings meteoSettings) + : inputTMin(inputTMin), inputTMax(inputTMax), inputPrec(inputPrec), firstMeteoDate(firstMeteoDate), lastMeteoDate(lastMeteoDate), meteoSettings(meteoSettings) { - return myHindcastSeries; } -std::vector WaterTable::getMyInterpolateSeries() const -{ - return myInterpolateSeries; -} void WaterTable::initializeWaterTable(Well myWell) { - this->well = myWell; + well = myWell; + getFirstDateWell(); getLastDateWell(); + for (int myMonthIndex = 0; myMonthIndex < 12; myMonthIndex++) { WTClimateMonthly[myMonthIndex] = NODATA; @@ -110,30 +32,58 @@ void WaterTable::initializeWaterTable(Well myWell) nrDaysPeriod = NODATA; nrObsData = 0; EF = NODATA; - NASH = NODATA; RMSE = NODATA; avgDailyCWB = NODATA; + errorStr = ""; +} + + +void WaterTable::setInputTMin(const std::vector &newInputTMin) +{ + inputTMin = newInputTMin; +} + +void WaterTable::setInputTMax(const std::vector &newInputTMax) +{ + inputTMax = newInputTMax; } +void WaterTable::setInputPrec(const std::vector &newInputPrec) +{ + inputPrec = newInputPrec; +} -bool WaterTable::computeWaterTable(Well myWell, int maxNrDays) +void WaterTable::cleanAllMeteoVector() +{ + inputTMin.clear(); + inputTMax.clear(); + inputPrec.clear(); + etpValues.clear(); + precValues.clear(); + + firstMeteoDate = QDate(); + lastMeteoDate = QDate(); +} + + +bool WaterTable::computeWaterTableParameters(Well myWell, int stepDays) { if (myWell.getObsDepthNr() == 0) { - error = "No WaterTable data loaded."; + errorStr = "No WaterTable data loaded."; return false; } initializeWaterTable(myWell); isClimateReady = computeWTClimate(); - if (! computeETP_allSeries()) + if (! computeETP_allSeries(true)) { return false; } - isCWBEquationReady = computeCWBCorrelation(maxNrDays); - if (!isCWBEquationReady) + isCWBEquationReady = computeCWBCorrelation(stepDays); + if (! isCWBEquationReady) { return false; } @@ -146,7 +96,7 @@ bool WaterTable::computeWTClimate() { if (well.getObsDepthNr() < 3) { - error = "Missing data"; + errorStr = "Missing data"; return false; } @@ -158,8 +108,7 @@ bool WaterTable::computeWTClimate() H_num.push_back(0); } - QMap myDepths = well.getObsDepths(); - QMapIterator it(myDepths); + QMapIterator it(well.depths); while (it.hasNext()) { it.next(); @@ -175,50 +124,88 @@ bool WaterTable::computeWTClimate() { if (H_num[myMonthIndex] < 2) { - error = "Missing watertable data: month " + QString::number(myMonthIndex+1); + errorStr = "Missing watertable data: month " + QString::number(myMonthIndex+1); return false; } WTClimateMonthly[myMonthIndex] = H_sum[myMonthIndex] / H_num[myMonthIndex]; } + + interpolation::cubicSplineYearInterpolate(WTClimateMonthly, WTClimateDaily); isClimateReady = true; - cubicSplineYearInterpolate(WTClimateMonthly, WTClimateDaily); + return true; } -bool WaterTable::computeETP_allSeries() +bool WaterTable::setMeteoData(QDate myDate, float tmin, float tmax, float prec) +{ + int index = firstMeteoDate.daysTo(myDate); + + if (index < int(etpValues.size()) && index < int(precValues.size())) + { + Crit3DDate date = Crit3DDate(myDate.day(), myDate.month(), myDate.year()); + etpValues[index] = dailyEtpHargreaves(tmin, tmax, date, well.getLatitude(), &meteoSettings); + precValues[index] = prec; + return true; + } + else + { + return false; + } +} + + +bool WaterTable::computeETP_allSeries(bool isUpdateAvgCWB) { etpValues.clear(); precValues.clear(); - double myLat, myLon; - gis::getLatLonFromUtm(gisSettings, well.getUtmX(), well.getUtmY(), &myLat, &myLon); + + if (inputTMin.size() != inputTMax.size() || inputTMin.size() != inputPrec.size()) + { + errorStr = "Wrong weather size"; + return false; + } + + float Tmin = NODATA; + float Tmax = NODATA; + float prec = NODATA; + float etp = NODATA; + double lat = well.getLatitude(); float sumCWB = 0; int nrValidDays = 0; - for (QDate myDate = firstMeteoDate; myDate<=lastMeteoDate; myDate=myDate.addDays(1)) + int nrOfData = (int)inputTMin.size(); + for (int i = 0; i < nrOfData; i++) { - Crit3DDate date(myDate.day(), myDate.month(), myDate.year()); - float Tmin = linkedMeteoPoint->getMeteoPointValueD(date, dailyAirTemperatureMin); - float Tmax = linkedMeteoPoint->getMeteoPointValueD(date, dailyAirTemperatureMax); - float prec = linkedMeteoPoint->getMeteoPointValueD(date, dailyPrecipitation); - float etp = dailyEtpHargreaves(Tmin, Tmax, date, myLat,&meteoSettings); + QDate currentDate = firstMeteoDate.addDays(i); + Crit3DDate myDate = Crit3DDate(currentDate.day(), currentDate.month(), currentDate.year()); + + Tmin = inputTMin[i]; + Tmax = inputTMax[i]; + prec = inputPrec[i]; + etp = dailyEtpHargreaves(Tmin, Tmax, myDate, lat, &meteoSettings); + etpValues.push_back(etp); precValues.push_back(prec); + if (etp != NODATA && prec != NODATA) { - sumCWB = sumCWB + (prec - etp); - nrValidDays = nrValidDays + 1; + sumCWB += prec - etp; + nrValidDays++; } } - if (nrValidDays > 0) - { - avgDailyCWB = sumCWB / nrValidDays; - } - else + if (isUpdateAvgCWB) { - error = "Missing data: " + QString::fromStdString(linkedMeteoPoint->name); - return false; + if (nrValidDays > 0) + { + avgDailyCWB = sumCWB / nrValidDays; + } + else + { + errorStr = "Missing data"; + return false; + } } return true; @@ -226,24 +213,25 @@ bool WaterTable::computeETP_allSeries() // Ricerca del periodo di correlazione migliore -bool WaterTable::computeCWBCorrelation(int maxNrDays) +bool WaterTable::computeCWBCorrelation(int stepDays) { - float bestR2 = 0; - float bestH0; - float bestAlfaCoeff; - int bestNrDays = NODATA; - QMap myDepths = well.getObsDepths(); std::vector myCWBSum; std::vector myObsWT; - float a; - float b; - float myR2; + float a = NODATA; + float b = NODATA; + float currentR2 = NODATA; + float bestR2 = 0; + float bestH0 = NODATA; + float bestAlfaCoeff = NODATA; + int bestNrDays = NODATA; - for (int nrDays = 90; nrDays <= maxNrDays; nrDays=nrDays+10) + int maxNrDays = 730; // two years + for (int nrDays = 90; nrDays <= maxNrDays; nrDays += stepDays) { myCWBSum.clear(); myObsWT.clear(); - QMapIterator it(myDepths); + QMapIterator it(well.depths); + while (it.hasNext()) { it.next(); @@ -256,77 +244,75 @@ bool WaterTable::computeCWBCorrelation(int maxNrDays) myObsWT.push_back(myValue); } } - statistics::linearRegression(myCWBSum, myObsWT, int(myCWBSum.size()), false, &a, &b, &myR2); - if (myR2 > bestR2) + + statistics::linearRegression(myCWBSum, myObsWT, int(myCWBSum.size()), false, &a, &b, ¤tR2); + if (currentR2 > bestR2) { - bestR2 = myR2; + bestR2 = currentR2; bestNrDays = nrDays; bestH0 = a; bestAlfaCoeff = b; } } - if (bestR2 > 0) - { - nrObsData = int(myObsWT.size()); - nrDaysPeriod = bestNrDays; - h0 = bestH0; - alpha = bestAlfaCoeff; - R2 = bestR2; - isCWBEquationReady = true; - return true; - } - else + + if (bestR2 < 0.1) { return false; } + + nrObsData = int(myObsWT.size()); + nrDaysPeriod = bestNrDays; + h0 = bestH0; + alpha = bestAlfaCoeff; + R2 = bestR2; + isCWBEquationReady = true; + + return true; } + // Climatic WaterBalance (CWB) on a nrDaysPeriod -float WaterTable::computeCWB(QDate myDate, int nrDays) +double WaterTable::computeCWB(QDate myDate, int nrDays) { - float sumCWB = 0; + double sumCWB = 0; int nrValidDays = 0; QDate actualDate; - float currentCWB; - float weight; - for (int shift = 1; shift<=nrDays; shift++) + for (int shift = 1; shift <= nrDays; shift++) { actualDate = myDate.addDays(-shift); int index = firstMeteoDate.daysTo(actualDate); - if (index >= 0 && index < precValues.size()) + if (index >= 0 && index < int(precValues.size())) { float etp = etpValues[index]; float prec = precValues[index]; if ( etp != NODATA && prec != NODATA) { - currentCWB = prec - etp; - weight = 1 - (float)shift/nrDays; - sumCWB = sumCWB + currentCWB * weight; - nrValidDays = nrValidDays + 1; + double currentCWB = double(prec - etp); + double weight = 1 - double(shift-1) / double(nrDays); + sumCWB += currentCWB * weight; + nrValidDays++; } } } if (nrValidDays < (nrDays * meteoSettings.getMinimumPercentage() / 100)) { - error = "Few Data"; + errorStr = "Few Data"; return NODATA; } + // Climate - float climateCWB = avgDailyCWB * nrDays * 0.5; + double climateCWB = avgDailyCWB * nrDays * 0.5; // conversion: from [mm] to [cm] - float computeCWB = (sumCWB - climateCWB) * 0.1; - - return computeCWB; + return (sumCWB - climateCWB) * 0.1; } // function to compute several statistical indices for watertable depth bool WaterTable::computeWaterTableIndices() { - QMap myDepths = well.getObsDepths(); - QMapIterator it(myDepths); + QMapIterator it(well.depths); std::vector myObs; std::vector myComputed; std::vector myClimate; @@ -349,7 +335,7 @@ bool WaterTable::computeWaterTableIndices() statistics::linearRegression(myObs, myComputed, int(myObs.size()), false, &myIntercept, &myCoeff, &R2); float mySum = 0; - float mySumError = 0; + float mySumerrorStr = 0; float mySumDiffClimate = 0; float mySumDiffAvg = 0; float myErr = 0; @@ -366,7 +352,7 @@ bool WaterTable::computeWaterTableIndices() for (int i=0; i myDepths = well.getObsDepths(); - QList keys = myDepths.keys(); + QList keys = well.depths.keys(); + + // check previuos and next observed data + int lastIndex = keys.size() - 1; int i = keys.indexOf(myDate); if (i != -1) // exact data found { - if (i>0) + indexPrev = i; + previousDate = keys[indexPrev]; + previosValue = well.depths[previousDate]; + indexNext = i; + nextDate = keys[indexNext]; + nextValue = well.depths[nextDate]; + } + else + { + if (keys[0] > myDate) { - indexPrev = i - 1; - previousDate = keys[indexPrev]; - previosValue = myDepths[previousDate]; + indexNext = 0; + nextDate = keys[indexNext]; + nextValue = well.depths[nextDate]; } - if (i < keys.size()-1) + else if (keys[lastIndex] < myDate) { - indexNext = i + 1; - nextDate = keys[indexNext]; - nextValue = myDepths[nextDate]; + indexPrev = lastIndex; + previousDate = keys[indexPrev]; + previosValue = well.depths[previousDate]; } - } - else - { - for (int i = 0; i myDate) - { - indexNext = i; - nextDate = keys[indexNext]; - nextValue = myDepths[nextDate]; - break; - } - else if (keys[i] < myDate && keys[i+1] > myDate) - { - indexPrev = i; - previousDate = keys[indexPrev]; - previosValue = myDepths[previousDate]; - indexNext = i + 1; - nextDate = keys[indexNext]; - nextValue = myDepths[nextDate]; - break; - } + for (int i = 0; i < lastIndex; i++) + if (keys[i] < myDate && keys[i+1] > myDate) + { + indexPrev = i; + previousDate = keys[indexPrev]; + previosValue = well.depths[previousDate]; + indexNext = i + 1; + nextDate = keys[indexNext]; + nextValue = well.depths[nextDate]; + break; + } } } + if (indexPrev != NODATA) { myWT = getWaterTableDaily(previousDate); @@ -567,7 +557,7 @@ bool WaterTable::getWaterTableHindcast(QDate myDate, float* myValue, float* myDe dT = previousDate.daysTo(nextDate); if (dT > WATERTABLE_MAXDELTADAYS * 2) { - if ( diffWithPrev <= diffWithNext) + if (diffWithPrev <= diffWithNext) { nextDz = NODATA; } @@ -577,22 +567,31 @@ bool WaterTable::getWaterTableHindcast(QDate myDate, float* myValue, float* myDe } } } + if (previousDz != NODATA && nextDz != NODATA) { dT = previousDate.daysTo(nextDate); - *myDelta = previousDz * (1 - (diffWithPrev / dT)) + nextDz * (1 - (diffWithNext / dT)); - *myDeltaDays = std::min(diffWithPrev, diffWithNext); + if (dT == 0) + { + *myDelta = previousDz; + *myDeltaDays = 0; + } + else + { + *myDelta = previousDz * (1.0 - (float(diffWithPrev) / float(dT))) + nextDz * (1.0 - (float(diffWithNext) / float(dT))); + *myDeltaDays = std::min(diffWithPrev, diffWithNext); + } } - else if ( previousDz!= NODATA) + else if (previousDz != NODATA) { dT = diffWithPrev; - *myDelta = previousDz * std::max((1 - (dT / WATERTABLE_MAXDELTADAYS)), 0); + *myDelta = previousDz * std::max((1.f - (float(dT) / float(WATERTABLE_MAXDELTADAYS))), 0.f); *myDeltaDays = dT; } - else if ( nextDz!= NODATA) + else if (nextDz != NODATA) { dT = diffWithNext; - *myDelta = nextDz * std::max((1 - (dT / WATERTABLE_MAXDELTADAYS)), 0); + *myDelta = nextDz * std::max((1.f - (float(dT) / float(WATERTABLE_MAXDELTADAYS))), 0.f); *myDeltaDays = dT; } else @@ -603,31 +602,35 @@ bool WaterTable::getWaterTableHindcast(QDate myDate, float* myValue, float* myDe } *myValue = myWT_computation + *myDelta; - return getWaterTableHindcast; + return true; } -void WaterTable::viewWaterTableSeries() + +void WaterTable::computeWaterTableSeries() { - QMap myDepths = well.getObsDepths(); - QMapIterator it(myDepths); + hindcastSeries.clear(); + interpolationSeries.clear(); - myDates.clear(); - myHindcastSeries.clear(); - myInterpolateSeries.clear(); - float myDepth; float myDelta; int myDeltaDays; - int numValues = well.getFirstDate().daysTo(lastMeteoDate) + 1; - for (int i = 0; i< numValues; i++) + firstDate = std::min(well.getFirstDate(), firstMeteoDate); + int numValues = firstDate.daysTo(lastMeteoDate) + 1; + + for (int i = 0; i < numValues; i++) { - QDate myDate = well.getFirstDate().addDays(i); - myDates.push_back(myDate); - //float computedValue = getWaterTableDaily(myDate.addDays(-1)); // LC in vb toglie un giorno ma non si capisce il motivo - float computedValue = getWaterTableDaily(myDate); - myHindcastSeries.push_back(computedValue); - //getWaterTableHindcast(myDate.addDays(-1), &myDepth, &myDelta, &myDeltaDays); // LC in vb toglie un giorno ma non si capisce il motivo - getWaterTableHindcast(myDate, &myDepth, &myDelta, &myDeltaDays); - myInterpolateSeries.push_back(myDepth); + QDate currentDate = firstDate.addDays(i); + + float currentDepth = getWaterTableDaily(currentDate); + hindcastSeries.push_back(currentDepth); + + if (getWaterTableInterpolation(currentDate, ¤tDepth, &myDelta, &myDeltaDays)) + { + interpolationSeries.push_back(currentDepth); + } + else + { + interpolationSeries.push_back(NODATA); + } } } diff --git a/agrolib/waterTable/waterTable.h b/agrolib/waterTable/waterTable.h index 1c64e31d..f6c9ece7 100644 --- a/agrolib/waterTable/waterTable.h +++ b/agrolib/waterTable/waterTable.h @@ -1,83 +1,102 @@ #ifndef WATERTABLE_H #define WATERTABLE_H -#include "well.h" -#include "meteoPoint.h" -#include "meteoGrid.h" +#ifndef WELL_H + #include "well.h" +#endif +#ifndef METEO_H + #include "meteo.h" +#endif +#ifndef GIS_H + #include "gis.h" +#endif #include -#define MAXWELLDISTANCE 5000 // distanza max: 10 km +#define MAXWELLDISTANCE 5000 // distanza max: 5 km #define WATERTABLE_MAXDELTADAYS 90 class WaterTable { public: - WaterTable(Crit3DMeteoPoint* linkedMeteoPoint, Crit3DMeteoSettings meteoSettings, gis::Crit3DGisSettings gisSettings); - QString getIdWell() const; - QDate getFirstDateWell(); - QDate getLastDateWell(); + float WTClimateMonthly[12]; + float WTClimateDaily[366]; + + QDate firstDate; + std::vector hindcastSeries; + std::vector interpolationSeries; + + WaterTable(std::vector &inputTMin, std::vector &inputTMax, std::vector &inputPrec, + QDate firstMeteoDate, QDate lastMeteoDate, Crit3DMeteoSettings meteoSettings); + void initializeWaterTable(Well myWell); - bool computeWaterTable(Well myWell, int maxNrDays); + bool computeWaterTableParameters(Well myWell, int stepDays); bool computeWTClimate(); - bool computeETP_allSeries(); - bool computeCWBCorrelation(int maxNrDays); - float computeCWB(QDate myDate, int nrDays); + bool computeETP_allSeries(bool isUpdateAvgCWB); + bool computeCWBCorrelation(int stepDays); + double computeCWB(QDate myDate, int nrDays); bool computeWaterTableIndices(); float getWaterTableDaily(QDate myDate); float getWaterTableClimate(QDate myDate); bool computeWaterTableClimate(QDate currentDate, int yearFrom, int yearTo, float* myValue); - bool getWaterTableHindcast(QDate myDate, float* myValue, float* myDelta, int* myDeltaDays); - void viewWaterTableSeries(); - QString getError() const; - - float getAlpha() const; - float getH0() const; - int getNrDaysPeriod() const; - float getR2() const; - float getRMSE() const; - float getNASH() const; - float getEF() const; - int getNrObsData() const; - - std::vector getMyDates() const; - std::vector getMyHindcastSeries() const; - std::vector getMyInterpolateSeries() const; - QMap getObsDepths(); + bool getWaterTableInterpolation(QDate myDate, float* myValue, float* myDelta, int* myDeltaDays); + void computeWaterTableSeries(); + + bool setMeteoData(QDate myDate, float tmin, float tmax, float prec); + + void setInputTMin(const std::vector &newInputTMin); + void setInputTMax(const std::vector &newInputTMax); + void setInputPrec(const std::vector &newInputPrec); + + void setFirstMeteoDate(QDate myDate) { firstMeteoDate = myDate; } + void setLastMeteoDate(QDate myDate) { lastMeteoDate = myDate; } + + QString getError() const { return errorStr; } + + double getAlpha() const { return alpha; } + double getH0() const { return h0; } + + float getR2() const { return R2; } + float getRMSE() const { return RMSE; } + float getEF() const { return EF; } + + int getNrDaysPeriod() const { return nrDaysPeriod; } + int getNrObsData() const { return nrObsData; } + + QString getIdWell() const { return well.getId(); } + QDate getFirstDateWell() { return well.getFirstDate(); } + QDate getLastDateWell() { return well.getLastDate(); } + + Well* getWell() { return &well; } + + void cleanAllMeteoVector(); private: - Crit3DMeteoPoint* linkedMeteoPoint; Crit3DMeteoSettings meteoSettings; - gis::Crit3DGisSettings gisSettings; - QDate firstDateWell; - QDate lastDateWell; + QDate firstMeteoDate; QDate lastMeteoDate; Well well; - QString error; + QString errorStr; + std::vector inputTMin; + std::vector inputTMax; + std::vector inputPrec; std::vector etpValues; std::vector precValues; int nrDaysPeriod; - float alpha; - float h0; + double alpha; + double h0; + float R2; float RMSE; - float NASH; float EF; bool isClimateReady; - float WTClimateMonthly[12]; - float WTClimateDaily[366]; int nrObsData; bool isCWBEquationReady; - float avgDailyCWB; //[mm] - - // graph - std::vector myDates; - std::vector myHindcastSeries; - std::vector myInterpolateSeries; + double avgDailyCWB; //[mm] }; #endif // WATERTABLE_H diff --git a/agrolib/waterTable/waterTable.pro b/agrolib/waterTable/waterTable.pro index c012e2a1..069634f6 100644 --- a/agrolib/waterTable/waterTable.pro +++ b/agrolib/waterTable/waterTable.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += widgets charts core xml +QT += core widgets charts QT -= gui TEMPLATE = lib @@ -24,7 +24,7 @@ win32:{ TARGET = waterTable } -INCLUDEPATH += ../crit3dDate ../mathFunctions ../meteo ../interpolation ../gis ../commonChartElements ../weatherGenerator +INCLUDEPATH += ../mathFunctions ../crit3dDate ../meteo ../gis ../commonChartElements SOURCES += \ dialogSelectWell.cpp \ diff --git a/agrolib/waterTable/waterTableChartView.cpp b/agrolib/waterTable/waterTableChartView.cpp index 83719422..ffd5d83c 100644 --- a/agrolib/waterTable/waterTableChartView.cpp +++ b/agrolib/waterTable/waterTableChartView.cpp @@ -1,12 +1,14 @@ #include "waterTableChartView.h" + WaterTableChartView::WaterTableChartView(QWidget *parent) : QChartView(new QChart(), parent) { obsDepthSeries = new QScatterSeries(); obsDepthSeries->setName("Observed"); - obsDepthSeries->setColor(Qt::green); - obsDepthSeries->setMarkerSize(8.0); + obsDepthSeries->setColor(QColor(0, 192, 255)); + obsDepthSeries->setBorderColor(QColor(0,0,1)); + obsDepthSeries->setMarkerSize(4.0); hindcastSeries = new QLineSeries(); hindcastSeries->setName("hindcast"); @@ -16,6 +18,13 @@ WaterTableChartView::WaterTableChartView(QWidget *parent) : interpolationSeries->setName("interpolation"); interpolationSeries->setColor(QColor(0,0,1)); + QPen pen; + pen.setWidth(2); + climateSeries = new QLineSeries(); + climateSeries->setName("climate"); + climateSeries->setPen(pen); + climateSeries->setColor(QColor(0, 200, 0, 255)); + axisX = new QDateTimeAxis(); axisX->setFormat("yyyy/MM"); axisY = new QValueAxis(); @@ -31,55 +40,71 @@ WaterTableChartView::WaterTableChartView(QWidget *parent) : m_tooltip->hide(); } -void WaterTableChartView::draw(std::vector myDates, std::vector myHindcastSeries, std::vector myInterpolateSeries, QMap obsDepths) + +void WaterTableChartView::drawWaterTable(WaterTable &waterTable, float maximumObservedDepth) { + axisY->setMax(maximumObservedDepth); // unit of observed watertable data, usually [cm] + axisY->setMin(0); + axisY->setLabelFormat("%d"); + axisY->setTickCount(16); - int nDays = myDates.size(); - QDateTime myDateTime; - myDateTime.setTime(QTime(0,0,0)); - for (int day = 0; day < nDays; day++) + QDateTime firstDateTime, lastDateTime; + int nrDays = int(waterTable.interpolationSeries.size()); + firstDateTime.setDate(waterTable.firstDate); + lastDateTime.setDate(waterTable.firstDate); + lastDateTime = lastDateTime.addDays(nrDays-1); + + axisX->setRange(firstDateTime, lastDateTime); + axisX->setTickCount(15); + + QDateTime currentDateTime = firstDateTime; + for (int day = 0; day < nrDays; day++) { - myDateTime.setDate(myDates[day]); - hindcastSeries->append(myDateTime.toMSecsSinceEpoch(), myHindcastSeries[day]); - interpolationSeries->append(myDateTime.toMSecsSinceEpoch(), myInterpolateSeries[day]); + QDate firstJanuary; + firstJanuary.setDate(currentDateTime.date().year(), 1, 1); + int doyIndex = firstJanuary.daysTo(currentDateTime.date()); // from 0 to 365 + + hindcastSeries->append(currentDateTime.toMSecsSinceEpoch(), waterTable.hindcastSeries[day]); + interpolationSeries->append(currentDateTime.toMSecsSinceEpoch(), waterTable.interpolationSeries[day]); + climateSeries->append(currentDateTime.toMSecsSinceEpoch(), waterTable.WTClimateDaily[doyIndex]); - if(obsDepths.contains(myDates[day])) + if(waterTable.getWell()->depths.contains(currentDateTime.date())) { - int myDepth = obsDepths[myDates[day]]; - obsDepthSeries->append(myDateTime.toMSecsSinceEpoch(), myDepth); + int myDepth = waterTable.getWell()->depths[currentDateTime.date()]; + obsDepthSeries->append(currentDateTime.toMSecsSinceEpoch(), myDepth); } - } + currentDateTime = currentDateTime.addDays(1); + } - axisY->setMax(300); - axisY->setMin(0); - axisY->setLabelFormat("%d"); - axisY->setTickCount(16); - axisX->setTickCount(15); - QDateTime firstDateTime; - firstDateTime.setDate(myDates[0]); - firstDateTime.setTime(QTime(0,0,0)); - QDateTime lastDateTime; - lastDateTime.setDate(myDates[myDates.size()-1]); - lastDateTime.setTime(QTime(0,0,0)); - axisX->setRange(firstDateTime, lastDateTime); - chart()->addSeries(obsDepthSeries); chart()->addSeries(hindcastSeries); + chart()->addSeries(climateSeries); chart()->addSeries(interpolationSeries); + chart()->addSeries(obsDepthSeries); + + obsDepthSeries->attachAxis(axisX); + obsDepthSeries->attachAxis(axisY); + hindcastSeries->attachAxis(axisX); + hindcastSeries->attachAxis(axisY); + interpolationSeries->attachAxis(axisX); + interpolationSeries->attachAxis(axisY); + climateSeries->attachAxis(axisX); + climateSeries->attachAxis(axisY); connect(obsDepthSeries, &QScatterSeries::hovered, this, &WaterTableChartView::tooltipObsDepthSeries); connect(hindcastSeries, &QLineSeries::hovered, this, &WaterTableChartView::tooltipLineSeries); connect(interpolationSeries, &QLineSeries::hovered, this, &WaterTableChartView::tooltipLineSeries); + foreach(QLegendMarker* marker, chart()->legend()->markers()) { marker->setVisible(true); marker->series()->setVisible(true); QObject::connect(marker, &QLegendMarker::clicked, this, &WaterTableChartView::handleMarkerClicked); } - return; } + void WaterTableChartView::tooltipObsDepthSeries(QPointF point, bool state) { diff --git a/agrolib/waterTable/waterTableChartView.h b/agrolib/waterTable/waterTableChartView.h index 8c4d9727..278f3b23 100644 --- a/agrolib/waterTable/waterTableChartView.h +++ b/agrolib/waterTable/waterTableChartView.h @@ -1,27 +1,33 @@ #ifndef WATERTABLECHARTVIEW_H #define WATERTABLECHARTVIEW_H -#include -#include -#include "waterTable.h" -#include "callout.h" - -class WaterTableChartView : public QChartView -{ - public: - WaterTableChartView(QWidget *parent = 0); - void draw(std::vector myDates, std::vector myHindcastSeries, std::vector myInterpolateSeries, QMap obsDepths); - void tooltipObsDepthSeries(QPointF point, bool state); - void tooltipLineSeries(QPointF point, bool state); - void handleMarkerClicked(); - QList exportInterpolationValues(); - private: - QScatterSeries* obsDepthSeries; - QLineSeries* hindcastSeries; - QLineSeries* interpolationSeries; - QDateTimeAxis* axisX; - QValueAxis* axisY; - Callout *m_tooltip; -}; + #include + #include + #include "waterTable.h" + #include "callout.h" + + class WaterTableChartView : public QChartView + { + public: + WaterTableChartView(QWidget *parent = 0); + + void drawWaterTable(WaterTable &waterTable, float maximumObservedDepth); + + void tooltipObsDepthSeries(QPointF point, bool state); + void tooltipLineSeries(QPointF point, bool state); + void handleMarkerClicked(); + QList exportInterpolationValues(); + + QDateTimeAxis* axisX; + + private: + QScatterSeries* obsDepthSeries; + QLineSeries* hindcastSeries; + QLineSeries* interpolationSeries; + QLineSeries* climateSeries; + + QValueAxis* axisY; + Callout *m_tooltip; + }; #endif // WATERTABLECHARTVIEW_H diff --git a/agrolib/waterTable/waterTableWidget.cpp b/agrolib/waterTable/waterTableWidget.cpp index be4c5b5d..de70e5dc 100644 --- a/agrolib/waterTable/waterTableWidget.cpp +++ b/agrolib/waterTable/waterTableWidget.cpp @@ -1,6 +1,7 @@ #include "waterTableWidget.h" +#include "dialogChangeAxis.h" -WaterTableWidget::WaterTableWidget(QString id, std::vector myDates, std::vector myHindcastSeries, std::vector myInterpolateSeries, QMap obsDepths) +WaterTableWidget::WaterTableWidget(const QString &id, WaterTable &waterTable, float maxObservedDepth) { this->setWindowTitle("Graph Id well: "+ id); this->resize(1240, 700); @@ -20,20 +21,38 @@ WaterTableWidget::WaterTableWidget(QString id, std::vector myDates, std:: menuBar->addMenu(editMenu); mainLayout->setMenuBar(menuBar); - QAction* exportInterpolation = new QAction(tr("&Export interpolation as csv"), this); + QAction* exportInterpolation = new QAction(tr("&Export interpolation as csv.."), this); + QAction* changeXAxis = new QAction(tr("&Change period (X axis).."), this); editMenu->addAction(exportInterpolation); + editMenu->addAction(changeXAxis); mainLayout->addLayout(plotLayout); setLayout(mainLayout); connect(exportInterpolation, &QAction::triggered, this, &WaterTableWidget::on_actionExportInterpolationData); + connect(changeXAxis, &QAction::triggered, this, &WaterTableWidget::on_actionChangeXAxis); - waterTableChartView->draw(myDates, myHindcastSeries, myInterpolateSeries, obsDepths); + waterTableChartView->drawWaterTable(waterTable, maxObservedDepth); } -void WaterTableWidget::on_actionExportInterpolationData() + +void WaterTableWidget::on_actionChangeXAxis() { + DialogChangeAxis changeAxisDialog(0, true); + + if (changeAxisDialog.result() == QDialog::Accepted) + { + QDateTime firstDate, lastDate; + firstDate.setDate(changeAxisDialog.getMinDate()); + lastDate.setDate(changeAxisDialog.getMaxDate()); + waterTableChartView->axisX->setRange(firstDate, lastDate); + waterTableChartView->update(); + } +} + +void WaterTableWidget::on_actionExportInterpolationData() +{ QString csvFileName = QFileDialog::getSaveFileName(this, tr("Save current data"), "", tr("csv files (*.csv)")); if (csvFileName != "") { @@ -65,12 +84,3 @@ void WaterTableWidget::on_actionExportInterpolationData() } } -WaterTableWidget::~WaterTableWidget() -{ - -} - -void WaterTableWidget::closeEvent(QCloseEvent *event) -{ - event->accept(); -} diff --git a/agrolib/waterTable/waterTableWidget.h b/agrolib/waterTable/waterTableWidget.h index 90e10261..ac8f440d 100644 --- a/agrolib/waterTable/waterTableWidget.h +++ b/agrolib/waterTable/waterTableWidget.h @@ -1,23 +1,28 @@ #ifndef WATERTABLEWIDGET_H #define WATERTABLEWIDGET_H -#include -#include + #include + #include -#include "waterTableChartView.h" + #include "waterTableChartView.h" -class WaterTableWidget : public QWidget -{ - Q_OBJECT -public: - WaterTableWidget(QString id, std::vector myDates, std::vector myHindcastSeries, std::vector myInterpolateSeries, QMap obsDepths); - ~WaterTableWidget(); - void closeEvent(QCloseEvent *event); - void on_actionExportInterpolationData(); + class WaterTableWidget : public QWidget + { + Q_OBJECT + public: + WaterTableWidget(const QString &id, WaterTable &waterTable, float maxObservedDepth); -private: - WaterTableChartView *waterTableChartView; + ~WaterTableWidget() { ; } -}; + void closeEvent(QCloseEvent *event) + { event->accept(); } + + private: + WaterTableChartView *waterTableChartView; + + void on_actionExportInterpolationData(); + void on_actionChangeXAxis(); + + }; #endif // WATERTABLEWIDGET_H diff --git a/agrolib/waterTable/well.cpp b/agrolib/waterTable/well.cpp index 908506fe..963a303b 100644 --- a/agrolib/waterTable/well.cpp +++ b/agrolib/waterTable/well.cpp @@ -1,41 +1,20 @@ +#include "commonConstants.h" #include "well.h" +#include Well::Well() { + lat = NODATA; + lon = NODATA; + utmX = NODATA; + utmY = NODATA; + id = ""; + depths.clear(); } -QString Well::getId() const -{ - return id; -} - -void Well::setId(const QString &newId) -{ - id = newId; -} - -double Well::getUtmX() const -{ - return utmX; -} - -void Well::setUtmX(double newUtmX) -{ - utmX = newUtmX; -} - -double Well::getUtmY() const -{ - return utmY; -} - -void Well::setUtmY(double newUtmY) -{ - utmY = newUtmY; -} -void Well::insertData(QDate myDate, int myValue) +void Well::insertData(QDate myDate, float myValue) { depths.insert(myDate, myValue); } @@ -45,10 +24,7 @@ int Well::getObsDepthNr() return depths.size(); } -QMap Well::getObsDepths() const -{ - return depths; -} + QDate Well::getFirstDate() { @@ -64,6 +40,7 @@ QDate Well::getFirstDate() return firstDate; } + QDate Well::getLastDate() { QList allDates = depths.keys(); @@ -77,3 +54,25 @@ QDate Well::getLastDate() } return lastDate; } + + +int Well::minValuesPerMonth() +{ + QMapIterator it(depths); + std::vector H_num; + for (int myMonthIndex = 0; myMonthIndex < 12; myMonthIndex++) + { + H_num.push_back(0); + } + while (it.hasNext()) + { + it.next(); + QDate myDate = it.key(); + int myMonth = myDate.month(); + int myMonthIndex = myMonth - 1; + H_num[myMonthIndex] = H_num[myMonthIndex] + 1; + } + + auto min = min_element(H_num.begin(), H_num.end()); + return *min; +} diff --git a/agrolib/waterTable/well.h b/agrolib/waterTable/well.h index fd05e4e0..9d26ca77 100644 --- a/agrolib/waterTable/well.h +++ b/agrolib/waterTable/well.h @@ -5,35 +5,43 @@ #include #include #include -#include "meteoPoint.h" class Well { public: + QMap depths; + Well(); - QString getId() const; - void setId(const QString &newId); - double getUtmX() const; - void setUtmX(double newUtmX); + QString getId() const { return id; } + void setId(const QString &newId) { id = newId; } + + double getUtmX() const { return utmX; } + void setUtmX(double newUtmX) { utmX = newUtmX; } + + double getUtmY() const { return utmY; } + void setUtmY(double newUtmY) { utmY = newUtmY; } + + double getLatitude() const { return lat; } + void setLatitude(double newLat) { lat = newLat; } - double getUtmY() const; - void setUtmY(double newUtmY); + double getLongitude() const { return lon; } + void setLongitude(double newLon) { lon = newLon; } - void insertData(QDate myDate, int myValue); + void insertData(QDate myDate, float myValue); QDate getFirstDate(); QDate getLastDate(); int getObsDepthNr(); - - QMap getObsDepths() const; + int minValuesPerMonth(); private: QString id; - double utmX; - double utmY; - QMap depths; + + double utmX, utmY; + double lat, lon; + QDate firstDate; QDate lastDate; }; diff --git a/agrolib/weatherGenerator/fileUtility.cpp b/agrolib/weatherGenerator/fileUtility.cpp index 0a481b6b..f20933b6 100644 --- a/agrolib/weatherGenerator/fileUtility.cpp +++ b/agrolib/weatherGenerator/fileUtility.cpp @@ -175,7 +175,7 @@ bool readMeteoDataCsv (const QString &fileName, char mySeparator, double noData, // Write the output of weather generator: a daily series of tmin, tmax, prec data -bool writeMeteoDataCsv(const QString &fileName, char separator, std::vector &dailyData) +bool writeMeteoDataCsv(const QString &fileName, char separator, std::vector &dailyData, bool isWaterTable) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { @@ -184,23 +184,49 @@ bool writeMeteoDataCsv(const QString &fileName, char separator, std::vector &dailyData); + bool writeMeteoDataCsv(const QString &fileName, char separator, std::vector &dailyData, bool isWaterTable); #endif // FILEUTILITY_H diff --git a/agrolib/weatherGenerator/parserXML.cpp b/agrolib/weatherGenerator/parserXML.cpp index f8775f41..a019b61c 100644 --- a/agrolib/weatherGenerator/parserXML.cpp +++ b/agrolib/weatherGenerator/parserXML.cpp @@ -52,54 +52,44 @@ void XMLSeasonalAnomaly::printInfo() qDebug() << ""; } + XMLScenarioAnomaly::XMLScenarioAnomaly() { - this->initialize(); // chiedere a Fausto perchĂ© non fare initialize direttamente qui + this->initialize(); } void XMLScenarioAnomaly::initialize() { - /* point.name = ""; point.code = ""; point.latitude = NODATA; point.longitude = NODATA; - point.info = ""; - - forecast.clear(); climatePeriod.yearFrom = NODATA; climatePeriod.yearTo = NODATA; - modelNumber = NODATA; - - modelName.clear(); - modelMember.clear(); + models.type.clear(); + models.value.clear(); + models.number = 0; repetitions = NODATA; anomalyYear = NODATA; - anomalySeason = ""; - */ } void XMLScenarioAnomaly::printInfo() { - /* qDebug() << "point.name = " << point.name; - qDebug() << "point.longitude = " << point.longitude; - qDebug() << "point.latitude = " << point.latitude; + //qDebug() << "point.longitude = " << point.longitude; + //qDebug() << "point.latitude = " << point.latitude; qDebug() << "climate first year = " << climatePeriod.yearFrom; qDebug() << "climate last year = " << climatePeriod.yearTo; - qDebug() << "number of models = " << modelNumber; - qDebug() << "models = " << modelName; - qDebug() << "number of members = " << modelMember; - qDebug() << "number of repetitions = " << repetitions; + qDebug() << "models = " << models.type; + qDebug() << "number of models = " << models.number; qDebug() << "anomaly year = " << anomalyYear; - qDebug() << "anomaly season = " << anomalySeason; + qDebug() << "number of repetitions = " << repetitions; qDebug() << ""; - */ } @@ -186,12 +176,22 @@ bool parseXMLSeasonal(const QString &xmlFileName, XMLSeasonalAnomaly &XMLAnomaly } else if ((myTag == "LAT") || (myTag == "LATITUDE")) { - XMLAnomaly.point.latitude = child.toElement().text().toFloat(); + bool ok; + XMLAnomaly.point.latitude = child.toElement().text().toFloat(&ok); + if (ok == false) + { + XMLAnomaly.point.latitude = NODATA; + } nrTokens++; } else if ((myTag == "LON") || (myTag == "LONGITUDE")) { - XMLAnomaly.point.longitude = child.toElement().text().toFloat(); + bool ok; + XMLAnomaly.point.longitude = child.toElement().text().toFloat(&ok); + if (ok == false) + { + XMLAnomaly.point.longitude = NODATA; + } nrTokens++; } else if (myTag == "INFO") @@ -320,7 +320,7 @@ bool parseXMLScenario(const QString &xmlFileName, XMLScenarioAnomaly &XMLAnomaly QDomNode child; QDomNode secondChild; - TXMLValuesList valuelist; + TXMLScenarioValuesList valuelist; QDomNode ancestor = xmlDoc.documentElement().firstChild(); QString myTag; @@ -389,6 +389,7 @@ bool parseXMLScenario(const QString &xmlFileName, XMLScenarioAnomaly &XMLAnomaly { models = child.toElement().text(); XMLAnomaly.models.value = models.split(","); + XMLAnomaly.models.number = XMLAnomaly.models.value.size(); nrTokens++; } child = child.nextSibling(); @@ -437,6 +438,7 @@ bool parseXMLScenario(const QString &xmlFileName, XMLScenarioAnomaly &XMLAnomaly else if (ancestor.toElement().tagName().toUpper() == "PERIOD") { child = ancestor.firstChild(); + counterVar = 0; while(! child.isNull()) { myTag = child.toElement().tagName().toUpper(); @@ -452,7 +454,7 @@ bool parseXMLScenario(const QString &xmlFileName, XMLScenarioAnomaly &XMLAnomaly if (myTag == "VAR") { secondChild = child.firstChild(); - counterVar = 0; + XMLAnomaly.period[counterTime].seasonalScenarios.push_back(valuelist); while(! secondChild.isNull()) { mySecondTag = secondChild.toElement().tagName().toUpper(); @@ -478,8 +480,9 @@ bool parseXMLScenario(const QString &xmlFileName, XMLScenarioAnomaly &XMLAnomaly } secondChild = secondChild.nextSibling(); - counterVar++; + } + counterVar++; } child = child.nextSibling(); } diff --git a/agrolib/weatherGenerator/parserXML.h b/agrolib/weatherGenerator/parserXML.h index 9e56ca20..a6f42f06 100644 --- a/agrolib/weatherGenerator/parserXML.h +++ b/agrolib/weatherGenerator/parserXML.h @@ -18,6 +18,7 @@ { QString type; QStringList value; + int number; }; struct TXMLScenarioClimateField { @@ -39,7 +40,7 @@ struct TXMLScenarioPeriod { QString type; - TXMLScenarioValuesList seasonalScenarios[4]; + std::vector seasonalScenarios; }; struct TXMLPoint diff --git a/agrolib/weatherGenerator/timeUtility.cpp b/agrolib/weatherGenerator/timeUtility.cpp index 84b1b2a6..e6ae768a 100644 --- a/agrolib/weatherGenerator/timeUtility.cpp +++ b/agrolib/weatherGenerator/timeUtility.cpp @@ -189,3 +189,36 @@ void setCorrectWgDoy(int wgDoy1, int wgDoy2, int predictionYear, int myYear, int } } } + +void setAnomalyMonthScenario(QString startingSeason, int *anomalyMonth1, int *anomalyMonth2) +{ + if(startingSeason == "DJF") + { + anomalyMonth1[0] = 12; anomalyMonth2[0] = 2; + anomalyMonth1[1] = 3; anomalyMonth2[1] = 5; + anomalyMonth1[2] = 6; anomalyMonth2[2] = 8; + anomalyMonth1[3] = 9; anomalyMonth2[3] = 11; + } + else if (startingSeason == "MAM") + { + anomalyMonth1[3] = 12; anomalyMonth2[3] = 2; + anomalyMonth1[0] = 3; anomalyMonth2[0] = 5; + anomalyMonth1[1] = 6; anomalyMonth2[1] = 8; + anomalyMonth1[2] = 9; anomalyMonth2[2] = 11; + } + else if (startingSeason == "JJA") + { + anomalyMonth1[2] = 12; anomalyMonth2[2] = 2; + anomalyMonth1[3] = 3; anomalyMonth2[3] = 5; + anomalyMonth1[0] = 6; anomalyMonth2[0] = 8; + anomalyMonth1[1] = 9; anomalyMonth2[1] = 11; + + } + else + { + anomalyMonth1[1] = 12; anomalyMonth2[1] = 2; + anomalyMonth1[2] = 3; anomalyMonth2[2] = 5; + anomalyMonth1[3] = 6; anomalyMonth2[3] = 8; + anomalyMonth1[0] = 9; anomalyMonth2[0] = 11; + } +} diff --git a/agrolib/weatherGenerator/timeUtility.h b/agrolib/weatherGenerator/timeUtility.h index 6d8bb385..88a3d9d0 100644 --- a/agrolib/weatherGenerator/timeUtility.h +++ b/agrolib/weatherGenerator/timeUtility.h @@ -6,6 +6,7 @@ class Crit3DDate; class QString; + class QDate; int getMonthsInPeriod(int month1, int month2); @@ -16,5 +17,7 @@ void setCorrectWgDoy(int wgDoy1, int wgDoy2, int predictionYear, int myYear, int &fixedWgDoy1, int &fixedWgDoy2); + void setAnomalyMonthScenario(QString startingSeason, int *anomalyMonth1, int *anomalyMonth2); + #endif // TIMEUTILITY diff --git a/agrolib/weatherGenerator/weatherGenerator.cpp b/agrolib/weatherGenerator/weatherGenerator.cpp index 320b0f40..0328dde9 100644 --- a/agrolib/weatherGenerator/weatherGenerator.cpp +++ b/agrolib/weatherGenerator/weatherGenerator.cpp @@ -5,7 +5,7 @@ \copyright 2016 Fausto Tomei, Laura Costantini - This file is part of CRITERIA3D. + This file is part of agrolib distribution . CRITERIA3D has been developed under contract issued by A.R.P.A. Emilia-Romagna CRITERIA3D is free software: you can redistribute it and/or modify @@ -162,7 +162,7 @@ void initializeDailyDataBasic(ToutputDailyMeteo* dailyData, Crit3DDate myDate) dailyData->maxTemp = NODATA; dailyData->minTemp = NODATA; dailyData->prec = NODATA; - + dailyData->waterTableDepth = NODATA; } @@ -231,14 +231,14 @@ void initializeWeather(TweatherGenClimate &wGen) mMeanPrecip[m] = mMeanPrecip[m] / (fWetDays[m] * float(daysInMonth)); } - cubicSplineYearInterpolate(mpww, wGen.daily.pww); - cubicSplineYearInterpolate(mpwd, wGen.daily.pwd); - cubicSplineYearInterpolate(mMeanDryTMax, wGen.daily.meanDryTMax); - cubicSplineYearInterpolate(mMeanPrecip, wGen.daily.meanPrecip); - cubicSplineYearInterpolate(mMeanWetTMax, wGen.daily.meanWetTMax); - cubicSplineYearInterpolate(mMeanTMin, wGen.daily.meanTMin); - cubicSplineYearInterpolate(mMinTempStd, wGen.daily.minTempStd); - cubicSplineYearInterpolate(mMaxTempStd, wGen.daily.maxTempStd); + interpolation::cubicSplineYearInterpolate(mpww, wGen.daily.pww); + interpolation::cubicSplineYearInterpolate(mpwd, wGen.daily.pwd); + interpolation::cubicSplineYearInterpolate(mMeanDryTMax, wGen.daily.meanDryTMax); + interpolation::cubicSplineYearInterpolate(mMeanPrecip, wGen.daily.meanPrecip); + interpolation::cubicSplineYearInterpolate(mMeanWetTMax, wGen.daily.meanWetTMax); + interpolation::cubicSplineYearInterpolate(mMeanTMin, wGen.daily.meanTMin); + interpolation::cubicSplineYearInterpolate(mMinTempStd, wGen.daily.minTempStd); + interpolation::cubicSplineYearInterpolate(mMaxTempStd, wGen.daily.maxTempStd); } @@ -315,114 +315,6 @@ float weibull (float dailyAvgPrec, float precThreshold) } - -/*! - * \brief Computes daily values starting from monthly averages using cubic spline - * \param monthlyAvg: vector of monthly averages (12 values) - * outputDailyValues: vector of interpolated daily values (366 values) -*/ -void cubicSplineYearInterpolate(float *monthlyAvg, float *outputDailyValues) -{ - double monthMid [16] = {-61, - 31, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 396}; - - for (int iMonth=0; iMonth<16; iMonth++) - { - monthMid[iMonth] += 15; - } - - double* avgMonthlyAmountLarger = new double[16]; - for (int iMonth = 0; iMonth < 12; iMonth++) - { - avgMonthlyAmountLarger[iMonth+2] = double(monthlyAvg[iMonth]); - } - - avgMonthlyAmountLarger[0] = double(monthlyAvg[10]); - avgMonthlyAmountLarger[1] = double(monthlyAvg[11]); - avgMonthlyAmountLarger[14] = double(monthlyAvg[0]); - avgMonthlyAmountLarger[15] = double(monthlyAvg[1]); - - for (int iDay=0; iDay<365; iDay++) - { - outputDailyValues[iDay] = interpolation::cubicSpline(iDay, monthMid, avgMonthlyAmountLarger, 16); - } - // leap years - outputDailyValues[365] = outputDailyValues[0]; - - delete [] avgMonthlyAmountLarger; -} - - -/*! - * \brief Computes daily values starting from monthly mean - * using quadratic spline - * original Campbell function - * it has a discontinuity between end and start of the year -*/ -void quadrSplineYearInterpolate(float *meanY, float *dayVal) -{ - float a[13] = {0}; - float b[14] = {0}; - float c[13] = {0}; - float aa[13] = {0}; - float bb[13] = {0}; - float cc[13] = {0}; - float d[14] = {0}; - float h[13] = {0}; - float t = 0; - - int i,j; - - int monthends [13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; - - d[1] = meanY[0] - meanY[11]; - h[0] = 30; - - for (i = 1; i<=12; i++) - { - if (i == 12) - d[i + 1] = meanY[0] - meanY[i-1]; - else - d[i + 1] = meanY[i] - meanY[i-1]; - - h[i] = monthends[i] - monthends[i - 1] - 1; - aa[i] = h[i - 1] / 6; - bb[i] = (h[i - 1] + h[i]) / 3; - cc[i] = h[i] / 6; - } - - for (i = 1; i<= 11; i++) - { - cc[i] = cc[i] / bb[i]; - d[i] = d[i] / bb[i]; - bb[i + 1] = bb[i + 1] - aa[i + 1] * cc[i]; - d[i + 1] = d[i + 1] - aa[i + 1] * d[i]; - } - - b[12] = d[12] / bb[12]; - for (i = 11; i>=1; i--) - b[i] = d[i] - cc[i] * b[i + 1]; - - for (i = 1; i<=12; i++) - { - a[i] = (b[i + 1] - b[i]) / (2 * h[i]); - c[i] = meanY[i-1] - (b[i + 1] + 2 * b[i]) * h[i] / 6; - } - - j = 0; - for (i = 1; i<=365; i++) - { - if (monthends[j] < i) - j = j + 1; - t = i - monthends[j - 1] - 1; - - dayVal[i-1] = c[j] + b[j] * t + a[j] * t * t; - - } - - dayVal[365] = dayVal[0]; -} - - /*! * \brief generates maximum and minimum temperature */ @@ -663,6 +555,89 @@ bool assignAnomalyPrec(float myAnomaly, int anomalyMonth1, int anomalyMonth2, } +bool assignXMLAnomalyScenario(XMLScenarioAnomaly* XMLAnomaly,int modelIndex, int* anomalyMonth1, int* anomalyMonth2, TweatherGenClimate& wGenNoAnomaly, TweatherGenClimate &wGen) +{ + //unsigned int i = 0; + QString myVar; + float myValue = 0.0; + + bool result; + + // loop for all XMLValuesList (Tmin, Tmax, TminVar, TmaxVar, Prec3M, Wetdays) + for (int iSeason=0;iSeason<4;iSeason++) + { + for (unsigned int iWeatherVariable = 0; iWeatherVariable < 4; iWeatherVariable++) + { + if (XMLAnomaly->period[iSeason].seasonalScenarios[iWeatherVariable].attribute.toUpper() == "ANOMALY") + { + myVar = XMLAnomaly->period[iSeason].seasonalScenarios[iWeatherVariable].type.toUpper(); + result = false; + //if (XMLAnomaly->forecast[i].value[modelIndex] != nullptr) + myValue = XMLAnomaly->period[iSeason].seasonalScenarios[iWeatherVariable].value[modelIndex].toFloat(); + //else + //myValue = NODATA; + + if (int(myValue) != int(NODATA)) + { + if ( (myVar == "TMIN") || (myVar == "AVGTMIN") ) + result = assignAnomalyNoPrec(myValue, anomalyMonth1[iSeason], anomalyMonth2[iSeason], wGenNoAnomaly.monthly.monthlyTmin, wGen.monthly.monthlyTmin); + else if ( (myVar == "TMAX") || (myVar == "AVGTMAX") ) + result = assignAnomalyNoPrec(myValue, anomalyMonth1[iSeason], anomalyMonth2[iSeason], wGenNoAnomaly.monthly.monthlyTmax, wGen.monthly.monthlyTmax); + else if ( (myVar == "PREC3M") || (myVar == "PREC") ) + result = assignAnomalyPrec(myValue, anomalyMonth1[iSeason], anomalyMonth2[iSeason], wGenNoAnomaly.monthly.sumPrec, wGen.monthly.sumPrec); + else if ( (myVar == "WETDAYSFREQUENCY") ) + result = assignAnomalyNoPrec(myValue, anomalyMonth1[iSeason], anomalyMonth2[iSeason], wGenNoAnomaly.monthly.fractionWetDays, wGen.monthly.fractionWetDays); + else if ( (myVar == "WETWETDAYSFREQUENCY") ) + result = assignAnomalyNoPrec(myValue, anomalyMonth1[iSeason], anomalyMonth2[iSeason], wGenNoAnomaly.monthly.probabilityWetWet, wGen.monthly.probabilityWetWet); + else if ( (myVar == "DELTATMAXDRYWET") ) + result = assignAnomalyNoPrec(myValue, anomalyMonth1[iSeason], anomalyMonth2[iSeason], wGenNoAnomaly.monthly.dw_Tmax, wGen.monthly.dw_Tmax); + + } + + + else + { + // not critical variables + if ((myVar == "DELTATMAXDRYWET") || (myVar == "WETWETDAYSFREQUENCY")) + result = true; + } + + if (result == false) + { + qDebug() << "wrong anomaly: " + myVar; + return false; + } + } + } + // move to the next season + //anomalyMonth1 = (anomalyMonth1 + 3)%12; + //if (anomalyMonth1 == 0) anomalyMonth1 +=12; + //anomalyMonth2 = (anomalyMonth2 + 3)%12; + //if (anomalyMonth2 == 0) anomalyMonth2 +=12; + } + /* DEBUG + QString anomaly="anomaly.txt"; + QFile file(anomaly); + file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); + QTextStream stream( &file ); + for (int m = 0; m < 12; m++) + { + stream << "month = " << m +1 << endl; + stream << "wGen.monthly.monthlyTmin = " << wGen.monthly.monthlyTmin[m] << endl; + stream << "wGen.monthly.monthlyTmax = " << wGen.monthly.monthlyTmax[m] << endl; + stream << "wGen.monthly.sumPrec = " << wGen.monthly.sumPrec[m] << endl; + stream << "wGen.monthly.stDevTmin[m] = " << wGen.monthly.stDevTmin[m] << endl; + stream << "wGen.monthly.stDevTmax = " << wGen.monthly.stDevTmax[m] << endl; + stream << "wGen.monthly.fractionWetDays[m] = " << wGen.monthly.fractionWetDays[m] << endl; + stream << "wGen.monthly.probabilityWetWet[m] = " << wGen.monthly.probabilityWetWet[m] << endl; + stream << "wGen.monthly.dw_Tmax[m] = " << wGen.monthly.dw_Tmax[m] << endl; + stream << "-------------------------------------------" << endl; + } + */ + + return true; +} + /*! * \name makeSeasonalForecast * \brief Generates a time series of daily data (Tmin, Tmax, Prec) @@ -671,7 +646,7 @@ bool assignAnomalyPrec(float myAnomaly, int anomalyMonth1, int anomalyMonth2, * Output is written on outputFileName (csv) */ bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAnomaly* XMLAnomaly, - TweatherGenClimate& wGenClimate, TinputObsData* lastYearDailyObsData, + TweatherGenClimate& wGenClimate, TinputObsData* dailyObsData, int nrRepetitions, int myPredictionYear, int wgDoy1, int wgDoy2, float rainfallThreshold) { @@ -690,8 +665,8 @@ bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAno // it checks if observed data includes the last 9 months before wgDoy1 int nrDaysBeforeWgDoy1; - if (! checkLastYearDate(lastYearDailyObsData->inputFirstDate, lastYearDailyObsData->inputLastDate, - lastYearDailyObsData->dataLength, myPredictionYear, wgDoy1, nrDaysBeforeWgDoy1)) + if (! checkLastYearDate(dailyObsData->inputFirstDate, dailyObsData->inputLastDate, + dailyObsData->dataLength, myPredictionYear, wgDoy1, nrDaysBeforeWgDoy1)) { qDebug() << "ERROR: observed data should include at least 9 months before wgDoy1"; return false; @@ -743,10 +718,10 @@ bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAno for (int tmp = 0; tmp < nrDaysBeforeWgDoy1; tmp++) { dailyPredictions[tmp].date = myDate; - obsIndex = difference(lastYearDailyObsData->inputFirstDate, dailyPredictions[tmp].date); - dailyPredictions[tmp].minTemp = lastYearDailyObsData->inputTMin[obsIndex]; - dailyPredictions[tmp].maxTemp = lastYearDailyObsData->inputTMax[obsIndex]; - dailyPredictions[tmp].prec = lastYearDailyObsData->inputPrecip[obsIndex]; + obsIndex = difference(dailyObsData->inputFirstDate, dailyPredictions[tmp].date); + dailyPredictions[tmp].minTemp = dailyObsData->inputTMin[obsIndex]; + dailyPredictions[tmp].maxTemp = dailyObsData->inputTMax[obsIndex]; + dailyPredictions[tmp].prec = dailyObsData->inputPrecip[obsIndex]; if ((int(dailyPredictions[tmp].maxTemp) == int(NODATA)) || (int(dailyPredictions[tmp].minTemp) == int(NODATA)) @@ -805,10 +780,11 @@ bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAno isLastMember = true; } // compute seasonal prediction - if (!computeSeasonalPredictions(lastYearDailyObsData, wGen, + std::vector indexWg; + if (! computeSeasonalPredictions(dailyObsData, wGen, myPredictionYear, myYear, nrRepetitions, wgDoy1, wgDoy2, rainfallThreshold, isLastMember, - dailyPredictions, &outputDataLength )) + dailyPredictions, &outputDataLength, indexWg)) { qDebug() << "Error in computeSeasonalPredictions"; return false; @@ -820,7 +796,280 @@ bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAno qDebug() << "\n>>> output:" << outputFileName; - writeMeteoDataCsv (outputFileName, separator, dailyPredictions); + writeMeteoDataCsv (outputFileName, separator, dailyPredictions, false); + + dailyPredictions.clear(); + + return true; +} + + +bool initializeWaterTableData(TinputObsData* dailyObsData, WaterTable *waterTable, + int predictionYear, int wgDoy1, int nrDaysBeforeWgDoy1, int daysWg) +{ + Crit3DDate seasonFirstDate = getDateFromDoy(predictionYear, wgDoy1); + Crit3DDate outputFirstDate = seasonFirstDate.addDays(-nrDaysBeforeWgDoy1); + + int firstIndex = difference(dailyObsData->inputFirstDate, outputFirstDate); + int totDays = firstIndex + nrDaysBeforeWgDoy1 + daysWg; + + std::vector inputTMin, inputTMax, inputPrec; + for (int i = 0; i < totDays; i++) + { + if (i < (firstIndex + nrDaysBeforeWgDoy1)) + { + inputTMin.push_back(dailyObsData->inputTMin[i]); + inputTMax.push_back(dailyObsData->inputTMax[i]); + inputPrec.push_back(dailyObsData->inputPrecip[i]); + } + else + { + // aggiungo giorni (vuoti) a watertable + inputTMin.push_back(NODATA); + inputTMax.push_back(NODATA); + inputPrec.push_back(NODATA); + } + } + + waterTable->setInputTMin(inputTMin); + waterTable->setInputTMax(inputTMax); + waterTable->setInputPrec(inputPrec); + + QDate firstDate = QDate(dailyObsData->inputFirstDate.year, dailyObsData->inputFirstDate.month, dailyObsData->inputFirstDate.day); + QDate lastDate = firstDate.addDays(totDays-1); + + waterTable->setFirstMeteoDate(firstDate); + waterTable->setLastMeteoDate(lastDate); + + waterTable->computeETP_allSeries(false); + + return true; +} + + +/*! + * \name makeSeasonalForecastWaterTable + * \brief Generates a time series of daily data (Tmin, Tmax, Prec, WaterTable depth) + * for a period of nrYears = numMembers * nrRepetitions + * Different members of anomalies loaded by xml files are added to the climate + * Output is written on outputFileName (csv) +*/ +bool makeSeasonalForecastWaterTable(QString outputFileName, char separator, XMLSeasonalAnomaly* XMLAnomaly, + TweatherGenClimate& wGenClimate, TinputObsData* dailyObsData, WaterTable *waterTable, + int nrRepetitions, int predictionYear, int wgDoy1, int wgDoy2, + float rainfallThreshold) +{ + // it checks if observed data includes the last 9 months before wgDoy1 + int nrDaysBeforeWgDoy1; + if (! checkLastYearDate(dailyObsData->inputFirstDate, dailyObsData->inputLastDate, + dailyObsData->dataLength, predictionYear, wgDoy1, nrDaysBeforeWgDoy1)) + { + qDebug() << "ERROR: observed data should include at least 9 months before wgDoy1"; + return false; + } + + Crit3DDate seasonLastDate; + int daysWg; + Crit3DDate seasonFirstDate = getDateFromDoy (predictionYear, wgDoy1); + if (wgDoy1 < wgDoy2) + { + seasonLastDate = getDateFromDoy (predictionYear, wgDoy2); + daysWg = wgDoy2 - wgDoy1 + 1; + } + else + { + seasonLastDate = getDateFromDoy (predictionYear+1, wgDoy2); + if (isLeapYear(predictionYear)) + { + daysWg = (366 - wgDoy1) + wgDoy2 + 1; + } + else + { + daysWg = (365 - wgDoy1) + wgDoy2 + 1; + } + } + + if (! initializeWaterTableData(dailyObsData, waterTable, predictionYear, wgDoy1, nrDaysBeforeWgDoy1, daysWg)) + { + qDebug() << "ERROR in initializeWaterTableData"; + return false; + } + + TweatherGenClimate wGen; + std::vector dailyPredictions; + + unsigned int nrMembers; // number of models into xml anomaly file + unsigned int nrYears; // number of years of the output series. It is the length of the virtual period where all the previsions (one for each model) are given one after another + unsigned int nrValues; // number of days between the first and the last prediction year + + nrMembers = 0; + for (int i = 0; imodelMember.size(); i++) + { + nrMembers += XMLAnomaly->modelMember[i].toUInt(); + } + + nrYears = nrMembers * unsigned(nrRepetitions); + int lastYear = predictionYear + signed(nrYears) - 1; + if (wgDoy2 < wgDoy1) lastYear++; + + Crit3DDate firstDatePrediction = seasonFirstDate.addDays(-nrDaysBeforeWgDoy1); + + unsigned int addday = 0; + for (int i = predictionYear; i <= lastYear; i++) + { + if (isLeapYear(i)) + addday++; + } + + nrValues = nrYears * 365 + addday +1; + if (nrValues <= 0) + { + qDebug() << "ERROR: wrong date"; + return false; + } + + dailyPredictions.resize(nrValues); + + float lastTmax = NODATA; + float lastTmin = NODATA; + + float wtDepth; + float myDelta; + int myDeltaDays; + + Crit3DDate myDate = firstDatePrediction; + for (int tmp = 0; tmp < nrDaysBeforeWgDoy1; tmp++) + { + dailyPredictions[tmp].date = myDate; + int obsIndex = difference(dailyObsData->inputFirstDate, dailyPredictions[tmp].date); + dailyPredictions[tmp].minTemp = dailyObsData->inputTMin[obsIndex]; + dailyPredictions[tmp].maxTemp = dailyObsData->inputTMax[obsIndex]; + dailyPredictions[tmp].prec = dailyObsData->inputPrecip[obsIndex]; + if (waterTable->getWaterTableInterpolation(QDate(myDate.year, myDate.month, myDate.day), &wtDepth, &myDelta, &myDeltaDays)) + { + dailyPredictions[tmp].waterTableDepth = wtDepth; + } + + if ((int(dailyPredictions[tmp].maxTemp) == int(NODATA)) + || (int(dailyPredictions[tmp].minTemp) == int(NODATA)) + || (int(dailyPredictions[tmp].prec) == int(NODATA))) + { + if (tmp == 0) + { + qDebug() << "ERROR: Missing data:" << QString::fromStdString(dailyPredictions[tmp].date.toStdString()); + return false; + } + else + { + qDebug() << "WARNING: Missing data:" << QString::fromStdString(dailyPredictions[tmp].date.toStdString()); + + if (int(dailyPredictions[tmp].maxTemp) == int(NODATA)) + dailyPredictions[tmp].maxTemp = lastTmax; + + if (int(dailyPredictions[tmp].minTemp) == int(NODATA)) + dailyPredictions[tmp].minTemp = lastTmin; + + if (int(dailyPredictions[tmp].prec) == int(NODATA)) + dailyPredictions[tmp].prec = 0; + } + } + else + { + lastTmax = dailyPredictions[tmp].maxTemp; + lastTmin = dailyPredictions[tmp].minTemp; + } + ++myDate; + } + qDebug() << "Observed OK"; + int outputDataLength = nrDaysBeforeWgDoy1; + + // store the climate without anomalies + wGen = wGenClimate; + int myYear = predictionYear; + bool isLastMember = false; + + int anomalyMonth1 = seasonFirstDate.month; + int anomalyMonth2 = seasonLastDate.month; + + for (unsigned int modelIndex = 0; modelIndex < nrMembers; modelIndex++) + { + // assign anomaly + if (! assignXMLAnomaly(XMLAnomaly, modelIndex, anomalyMonth1, anomalyMonth2, wGenClimate, wGen)) + { + qDebug() << "Error in Scenario: assignXMLAnomaly returns false"; + return false; + } + + if (modelIndex == nrMembers-1 ) + { + isLastMember = true; + } + // compute seasonal prediction + std::vector indexWg; + if (! computeSeasonalPredictions(dailyObsData, wGen, + predictionYear, myYear, nrRepetitions, + wgDoy1, wgDoy2, rainfallThreshold, isLastMember, + dailyPredictions, &outputDataLength, indexWg)) + { + qDebug() << "Error in computeSeasonalPredictions"; + return false; + } + if (indexWg.size() != 0) + { + QDate myDate(seasonFirstDate.year, seasonFirstDate.month, seasonFirstDate.day); + QDate lastDate(seasonLastDate.year, seasonLastDate.month, seasonLastDate.day); + for (int currentIndex = indexWg[0]; currentIndex <= indexWg[indexWg.size()-1]; currentIndex++) + { + float tmin = dailyPredictions[currentIndex].minTemp; + float tmax = dailyPredictions[currentIndex].maxTemp; + float prec = dailyPredictions[currentIndex].prec; + if (isLastMember && myDate>lastDate) + { + myDate.setDate(myDate.year()-1, myDate.month(), myDate.day()); // l'ultimo membro può prendere 2 periodi di wg + } + if (waterTable->setMeteoData(myDate, tmin, tmax, prec)) + { + if (waterTable->getWaterTableInterpolation(myDate, &wtDepth, &myDelta, &myDeltaDays)) + { + dailyPredictions[currentIndex].waterTableDepth = wtDepth; + } + } + myDate = myDate.addDays(1); + } + } + // next model + myYear = myYear + nrRepetitions; + } + + qDebug() << "\n>>> output:" << outputFileName; + + // copy all waterTableDepth outside wg period + int fixWgDoy1 = wgDoy1; + int fixWgDoy2 = wgDoy2; + int index = 0; + QDate firstDate(dailyPredictions[0].date.year, dailyPredictions[0].date.month, dailyPredictions[0].date.day); + QDate lastDate = firstDate.addDays(nrValues); + + for (QDate myDate = firstDate; myDate < lastDate; myDate=myDate.addDays(1)) + { + setCorrectWgDoy(wgDoy1, wgDoy2, predictionYear, myDate.year(), fixWgDoy1, fixWgDoy2); + if (! isWGDate(Crit3DDate(myDate.day(), myDate.month(), myDate.year()), fixWgDoy1, fixWgDoy2) + && dailyPredictions[index].waterTableDepth == NODATA) + { + for (int indexToBeCopyed = 0; indexToBeCopyed < 366; indexToBeCopyed++) + { + if (dailyPredictions[indexToBeCopyed].date.month == myDate.month() && dailyPredictions[indexToBeCopyed].date.day == myDate.day() && dailyPredictions[indexToBeCopyed].waterTableDepth != NODATA) + { + dailyPredictions[index].waterTableDepth = dailyPredictions[indexToBeCopyed].waterTableDepth; + break; + } + } + + } + index++; + } + + writeMeteoDataCsv (outputFileName, separator, dailyPredictions, true); dailyPredictions.clear(); @@ -835,13 +1084,13 @@ bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAno Period between wgDoy1 and wgDoy2 is produced by the WG Others data are a copy of the observed data of predictionYear Weather generator climate is stored in wgClimate - Observed data (Tmin, Tmax, Prec) are in lastYearDailyObsData + Observed data (Tmin, Tmax, Prec) are in dailyObsData \return outputDailyData */ -bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGenClimate &wgClimate, +bool computeSeasonalPredictions(TinputObsData *dailyObsData, TweatherGenClimate &wgClimate, int predictionYear, int firstYear, int nrRepetitions, int wgDoy1, int wgDoy2, float rainfallThreshold, bool isLastMember, - std::vector& outputDailyData, int *outputDataLength) + std::vector& outputDailyData, int *outputDataLength, std::vector& indexWg) { Crit3DDate myDate, obsDate; @@ -851,8 +1100,6 @@ bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGen int fixWgDoy1 = wgDoy1; int fixWgDoy2 = wgDoy2; - // TODO etp e falda - currentIndex = *outputDataLength; firstDate = outputDailyData[currentIndex-1].date.addDays(1); @@ -864,13 +1111,15 @@ bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGen if (isLastMember) { if ( (!isLeapYear(predictionYear) && !isLeapYear(lastYear)) || (isLeapYear(predictionYear) && isLeapYear(lastYear))) + { lastDate = getDateFromDoy(lastYear,wgDoy2); + } else { if(isLeapYear(predictionYear) && wgDoy2 >= 60 ) - lastDate = getDateFromDoy(lastYear,wgDoy2-1); + lastDate = getDateFromDoy(lastYear, wgDoy2-1); if(isLeapYear(lastYear) && wgDoy2 >= 59 ) - lastDate = getDateFromDoy(lastYear,wgDoy2+1); + lastDate = getDateFromDoy(lastYear, wgDoy2+1); } } else @@ -886,7 +1135,9 @@ bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGen if (isLastMember) { if ( (!isLeapYear(predictionYear+1) && !isLeapYear(lastYear)) || (isLeapYear(predictionYear+1) && isLeapYear(lastYear))) + { lastDate = getDateFromDoy(lastYear, wgDoy2); + } else { if(isLeapYear(predictionYear+1) && wgDoy2 >= 60) @@ -920,6 +1171,7 @@ bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGen outputDailyData[currentIndex].maxTemp = getTMax(myDoy, rainfallThreshold, wgClimate); outputDailyData[currentIndex].minTemp = getTMin(myDoy, rainfallThreshold, wgClimate); outputDailyData[currentIndex].prec = getPrecip(myDoy, rainfallThreshold, wgClimate); + indexWg.push_back(currentIndex); } else { @@ -932,13 +1184,13 @@ bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGen else if (myDoy > fixWgDoy2) obsDate.year = predictionYear-1; - obsIndex = difference(lastYearDailyObsData->inputFirstDate, obsDate); + obsIndex = difference(dailyObsData->inputFirstDate, obsDate); - if ( obsIndex >= 0 && obsIndex <= lastYearDailyObsData->dataLength ) + if ( obsIndex >= 0 && obsIndex <= dailyObsData->dataLength ) { - outputDailyData[currentIndex].maxTemp = lastYearDailyObsData->inputTMax[obsIndex]; - outputDailyData[currentIndex].minTemp = lastYearDailyObsData->inputTMin[obsIndex]; - outputDailyData[currentIndex].prec = lastYearDailyObsData->inputPrecip[obsIndex]; + outputDailyData[currentIndex].maxTemp = dailyObsData->inputTMax[obsIndex]; + outputDailyData[currentIndex].minTemp = dailyObsData->inputTMin[obsIndex]; + outputDailyData[currentIndex].prec = dailyObsData->inputPrecip[obsIndex]; } else { @@ -993,159 +1245,3 @@ bool computeClimate(TweatherGenClimate &wgClimate, int firstYear, int nrRepetiti return true; } -bool makeScenario(QString outputFileName, char separator, XMLSeasonalAnomaly* XMLAnomaly, - TweatherGenClimate& wGenClimate, - int nrRepetitions, int myPredictionYear, int wgDoy1, int wgDoy2, - float rainfallThreshold) -{ - /*TweatherGenClimate wGen; - std::vector dailyPredictions; - - Crit3DDate myFirstDatePrediction, seasonFirstDate, seasonLastDate; - - unsigned int nrMembers; // number of models into xml anomaly file - unsigned int nrYears; // number of years of the output series. It is the length of the virtual period where all the previsions (one for each model) are given one after another - unsigned int nrValues; // number of days between the first and the last prediction year - int firstYear, lastYear, myYear; - unsigned int obsIndex; - unsigned int addday = 0; - bool isLastMember = false; - - // it checks if observed data includes the last 9 months before wgDoy1 - int nrDaysBeforeWgDoy1; - if (! checkLastYearDate(lastYearDailyObsData->inputFirstDate, lastYearDailyObsData->inputLastDate, - lastYearDailyObsData->dataLength, myPredictionYear, wgDoy1, nrDaysBeforeWgDoy1)) - { - qDebug() << "ERROR: observed data should include at least 9 months before wgDoy1"; - return false; - } - - nrMembers = 0; - for (int i = 0; imodelMember.size(); i++) - { - nrMembers += XMLAnomaly->modelMember[i].toUInt(); - } - - nrYears = nrMembers * unsigned(nrRepetitions); - - firstYear = myPredictionYear; - - // wgDoy1 within myPredictionYear, wgDoy2 within myPredictionYear+1 - if (wgDoy1 < wgDoy2) - lastYear = firstYear + signed(nrYears) - 1; - else - lastYear = firstYear + signed(nrYears); - - seasonFirstDate = getDateFromDoy (myPredictionYear, wgDoy1); - if (wgDoy1 < wgDoy2) - seasonLastDate = getDateFromDoy (myPredictionYear, wgDoy2); - else - seasonLastDate = getDateFromDoy (myPredictionYear+1, wgDoy2); - - myFirstDatePrediction = seasonFirstDate.addDays(-nrDaysBeforeWgDoy1); - - for (int i = myPredictionYear; i <= lastYear; i++) - { - if (isLeapYear(i)) - addday++; - } - - nrValues = nrYears * 365 + addday +1; - if (nrValues <= 0) - { - qDebug() << "ERROR: wrong date"; - return false; - } - - dailyPredictions.resize(nrValues); - - // copy the last 9 months before wgDoy1 - float lastTmax = NODATA; - float lastTmin = NODATA; - Crit3DDate myDate = myFirstDatePrediction; - for (int tmp = 0; tmp < nrDaysBeforeWgDoy1; tmp++) - { - dailyPredictions[tmp].date = myDate; - obsIndex = difference(lastYearDailyObsData->inputFirstDate, dailyPredictions[tmp].date); - dailyPredictions[tmp].minTemp = lastYearDailyObsData->inputTMin[obsIndex]; - dailyPredictions[tmp].maxTemp = lastYearDailyObsData->inputTMax[obsIndex]; - dailyPredictions[tmp].prec = lastYearDailyObsData->inputPrecip[obsIndex]; - - if ((int(dailyPredictions[tmp].maxTemp) == int(NODATA)) - || (int(dailyPredictions[tmp].minTemp) == int(NODATA)) - || (int(dailyPredictions[tmp].prec) == int(NODATA))) - { - if (tmp == 0) - { - qDebug() << "ERROR: Missing data:" << QString::fromStdString(dailyPredictions[tmp].date.toStdString()); - return false; - } - else - { - qDebug() << "WARNING: Missing data:" << QString::fromStdString(dailyPredictions[tmp].date.toStdString()); - - if (int(dailyPredictions[tmp].maxTemp) == int(NODATA)) - dailyPredictions[tmp].maxTemp = lastTmax; - - if (int(dailyPredictions[tmp].minTemp) == int(NODATA)) - dailyPredictions[tmp].minTemp = lastTmin; - - if (int(dailyPredictions[tmp].prec) == int(NODATA)) - dailyPredictions[tmp].prec = 0; - } - } - else - { - lastTmax = dailyPredictions[tmp].maxTemp; - lastTmin = dailyPredictions[tmp].minTemp; - } - ++myDate; - } - - qDebug() << "Observed OK"; - int outputDataLength = nrDaysBeforeWgDoy1; - - // store the climate without anomalies - wGen = wGenClimate; - myYear = firstYear; - - // first month of my season - int anomalyMonth1 = seasonFirstDate.month; - // last month of my season - int anomalyMonth2 = seasonLastDate.month; - - for (unsigned int modelIndex = 0; modelIndex < nrMembers; modelIndex++) - { - // assign anomaly - if ( !assignXMLAnomaly(XMLAnomaly, modelIndex, anomalyMonth1, anomalyMonth2, wGenClimate, wGen)) - { - qDebug() << "Error in Scenario: assignXMLAnomaly returns false"; - return false; - } - - if (modelIndex == nrMembers-1 ) - { - isLastMember = true; - } - // compute seasonal prediction - if (!computeSeasonalPredictions(lastYearDailyObsData, wGen, - myPredictionYear, myYear, nrRepetitions, - wgDoy1, wgDoy2, rainfallThreshold, isLastMember, - dailyPredictions, &outputDataLength )) - { - qDebug() << "Error in computeSeasonalPredictions"; - return false; - } - - // next model - myYear = myYear + nrRepetitions; - } - - qDebug() << "\n>>> output:" << outputFileName; - - writeMeteoDataCsv (outputFileName, separator, dailyPredictions); - - dailyPredictions.clear(); - */ - return true; -} diff --git a/agrolib/weatherGenerator/weatherGenerator.h b/agrolib/weatherGenerator/weatherGenerator.h index 6fa5e412..50af3416 100644 --- a/agrolib/weatherGenerator/weatherGenerator.h +++ b/agrolib/weatherGenerator/weatherGenerator.h @@ -9,6 +9,10 @@ #include "parserXML.h" #endif + #ifndef WATERTABLE_H + #include "waterTable.h" + #endif + struct TinputObsData { Crit3DDate inputFirstDate; @@ -72,9 +76,10 @@ struct ToutputDailyMeteo { Crit3DDate date; - float minTemp; - float maxTemp; - float prec; + float minTemp; // [C] + float maxTemp; // [C] + float prec; // [mm] + float waterTableDepth; // [m] }; void initializeDailyDataBasic(ToutputDailyMeteo* dailyData, Crit3DDate myDate); @@ -92,8 +97,6 @@ bool markov(float pwd, float pww, bool isWetPreviousDay); float weibull (float mean, float precThreshold); - void cubicSplineYearInterpolate(float *monthlyAvg, float *outputDailyValues); - void quadrSplineYearInterpolate(float *meanY, float *dayVal); void genTemps(float *tMax, float *tMin, float meanTMax, float meanTMin, float stdMax, float stdMin, float *resTMaxPrev, float *resTMinPrev); @@ -108,26 +111,30 @@ bool assignAnomalyPrec(float myAnomaly, int anomalyMonth1, int anomalyMonth2, float* myWGMonthlyVarNoAnomaly, float* myWGMonthlyVar); + bool assignXMLAnomalyScenario(XMLScenarioAnomaly* XMLAnomaly, int modelIndex, int *anomalyMonth1, int *anomalyMonth2, + TweatherGenClimate& wGenNoAnomaly, TweatherGenClimate &wGen); bool makeSeasonalForecast(QString outputFileName, char separator, XMLSeasonalAnomaly* XMLAnomaly, - TweatherGenClimate& wGenClimate, TinputObsData* lastYearDailyObsData, + TweatherGenClimate& wGenClimate, TinputObsData* dailyObsData, int numRepetitions, int myPredictionYear, int wgDoy1, int wgDoy2, float rainfallThreshold); - bool computeSeasonalPredictions(TinputObsData *lastYearDailyObsData, TweatherGenClimate& wgClimate, + bool initializeWaterTableData(TinputObsData* dailyObsData, WaterTable *waterTable, + int predictionYear, int wgDoy1, int nrDaysBeforeWgDoy1, int daysWg); + + bool makeSeasonalForecastWaterTable(QString outputFileName, char separator, XMLSeasonalAnomaly* XMLAnomaly, + TweatherGenClimate& wGenClimate, TinputObsData* dailyObsData, WaterTable *waterTable, + int nrRepetitions, int myPredictionYear, int wgDoy1, int wgDoy2, float rainfallThreshold); + + bool computeSeasonalPredictions(TinputObsData *dailyObsData, TweatherGenClimate& wgClimate, int predictionYear, int firstYear, int nrRepetitions, int wgDoy1, int wgDoy2, float minPrec, bool isLastMember, - std::vector &outputDailyData, int *outputDataLength); + std::vector &outputDailyData, int *outputDataLength, std::vector &indexWg); bool computeClimate(TweatherGenClimate &wgClimate, int firstYear, int nrRepetitions, float rainfallThreshold, std::vector &outputDailyData); void clearInputData(TinputObsData &myData); - bool makeScenario(QString outputFileName, char separator, XMLSeasonalAnomaly* XMLAnomaly, - TweatherGenClimate& wGenClimate, - int nrRepetitions, int myPredictionYear, int wgDoy1, int wgDoy2, - float rainfallThreshold); - #endif // WEATHERGENERATOR_H diff --git a/agrolib/weatherGenerator/weatherGenerator.pro b/agrolib/weatherGenerator/weatherGenerator.pro index 0d932c35..d75fba51 100644 --- a/agrolib/weatherGenerator/weatherGenerator.pro +++ b/agrolib/weatherGenerator/weatherGenerator.pro @@ -28,7 +28,7 @@ win32:{ } -INCLUDEPATH += ../crit3dDate ../mathFunctions +INCLUDEPATH += ../crit3dDate ../mathFunctions ../meteo ../gis ../waterTable SOURCES += \ timeUtility.cpp \ diff --git a/agrolib/weatherGenerator/wgClimate.cpp b/agrolib/weatherGenerator/wgClimate.cpp index 11312849..a9743c08 100644 --- a/agrolib/weatherGenerator/wgClimate.cpp +++ b/agrolib/weatherGenerator/wgClimate.cpp @@ -561,8 +561,8 @@ bool computeWG2DClimate(int nrDays, Crit3DDate inputFirstDate, float *inputTMin, /*! * \brief Generates a climate starting from daily weather */ -bool climateGenerator(int nrData, TinputObsData climateDailyObsData, Crit3DDate climateDateIni, Crit3DDate climateDateFin, float precThreshold, float minPrecData, TweatherGenClimate* wGen) - +bool climateGenerator(int nrData, TinputObsData climateDailyObsData, Crit3DDate climateDateIni, + Crit3DDate climateDateFin, float precThreshold, float minPrecData, TweatherGenClimate* wGen) { unsigned int nrDays; int startIndex;