diff --git a/pom.xml b/pom.xml index f8f318ca799de29f0ea620f4763d6ca31ed46c08..f6f8b17c5199ffc8a0f4e43e8306526d519dd71b 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ <groupId>no.nibio.vips.model</groupId> <artifactId>DayDegreesModel</artifactId> - <version>0.1.0</version> + <version>0.1.1-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> diff --git a/src/main/java/no/nibio/vips/model/daydegreemodel/DataMatrix.java b/src/main/java/no/nibio/vips/model/daydegreemodel/DataMatrix.java new file mode 100644 index 0000000000000000000000000000000000000000..f78e3a43cde0c8b59eda65c75660404631dd3796 --- /dev/null +++ b/src/main/java/no/nibio/vips/model/daydegreemodel/DataMatrix.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of PsilaRosaeTempModel. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package no.nibio.vips.model.daydegreemodel; + +import no.nibio.vips.util.DateMap; + +/** + * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +public class DataMatrix extends DateMap{ + public final static String TMD = "TMD"; + public final static String TMD0C = "TMD0C"; +} + diff --git a/src/main/java/no/nibio/vips/model/daydegreemodel/DayDegreeModel.java b/src/main/java/no/nibio/vips/model/daydegreemodel/DayDegreeModel.java index 8b137891791fe96927ad78e64b0aad7bded08bdc..4d354af04ed1f5ce899ada3810b0c49dd763a0ad 100644 --- a/src/main/java/no/nibio/vips/model/daydegreemodel/DayDegreeModel.java +++ b/src/main/java/no/nibio/vips/model/daydegreemodel/DayDegreeModel.java @@ -1 +1,318 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of PsilaRosaeTempModel. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package no.nibio.vips.model.daydegreemodel; + +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; +import no.nibio.vips.entity.ModelConfiguration; +import no.nibio.vips.entity.Result; +import no.nibio.vips.entity.ResultImpl; +import no.nibio.vips.entity.WeatherObservation; +import no.nibio.vips.i18n.I18nImpl; +import no.nibio.vips.model.ConfigValidationException; +import no.nibio.vips.model.Model; +import no.nibio.vips.model.ModelExcecutionException; +import no.nibio.vips.model.ModelId; +import no.nibio.vips.util.ModelUtil; +import no.nibio.vips.util.CommonNamespaces; +import no.nibio.vips.util.InvalidAggregationTypeException; +import no.nibio.vips.util.WeatherElements; +import no.nibio.vips.util.WeatherObservationListException; +import no.nibio.vips.util.WeatherUtil; + +/** + * @copyright 2016-2021 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor J. Johansen <tor.johansen@nibio.no> (Model research) + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> (Programming) + */ +public class DayDegreeModel extends I18nImpl implements Model { + + public final static ModelId MODEL_ID = new ModelId("DAYDEGREES"); + + private final ModelUtil modelUtil; + + private TimeZone timeZone; + private DataMatrix dataMatrix; + + private List<WeatherObservation> TM; // Temporary storage of hourly values + private final Double dayDegreeBaseTemp = 0.0; + + // Threshold values + //private final Double THRESHOLD_1 = 260.0; + //private final Double THRESHOLD_2 = 360.0; + //private final Double THRESHOLD_3 = 560.0; + + public DayDegreeModel() + { + super("no.nibio.vips.model.psilarosaetempmodel.texts"); + this.modelUtil = new ModelUtil(); + } + + @Override + public List<Result> getResult() throws ModelExcecutionException { + this.calculateTemperatureSum(DataMatrix.TMD, DataMatrix.TMD0C); + + List<Result> retVal = new ArrayList<>(); + Date currentDate = this.dataMatrix.getFirstDateWithParameterValue(DataMatrix.TMD0C); + Calendar cal = Calendar.getInstance(this.timeZone); + DecimalFormat dFormat = new DecimalFormat("###.##"); + + while(this.dataMatrix.getParamDoubleValueForDate(currentDate, DataMatrix.TMD0C) != null) + { + Result result = new ResultImpl(); + result.setValidTimeStart(currentDate); + Double TMCurrentDate = ((WeatherObservation) this.dataMatrix.getParamValueForDate(currentDate, DataMatrix.TMD)).getValue(); + Double TMD0C = this.dataMatrix.getParamDoubleValueForDate(currentDate, DataMatrix.TMD0C); + + + + /* + result.setValue(CommonNamespaces.NS_WEATHER, DataMatrix.TMD, dFormat.format(TMCurrentDate)); + result.setValue(CommonNamespaces.NS_WEATHER, DataMatrix.TMDD5C, dFormat.format(TMDD5C)); + result.setValue(CommonNamespaces.NS_WEATHER, DataMatrix.TMD5C, dFormat.format(TMD5C)); + result.setValue(PsilaRosaeTempModel.MODEL_ID.toString(), "THRESHOLD_1", dFormat.format(this.THRESHOLD_1)); + result.setValue(PsilaRosaeTempModel.MODEL_ID.toString(), "THRESHOLD_2", dFormat.format(this.THRESHOLD_2)); + result.setValue(PsilaRosaeTempModel.MODEL_ID.toString(), "THRESHOLD_3", dFormat.format(this.THRESHOLD_3)); + + + Integer warningStatus = Result.WARNING_STATUS_NO_RISK; + if(TMDD5C >= this.THRESHOLD_1) + { + warningStatus = Result.WARNING_STATUS_MINOR_RISK; + } + if(TMDD5C >= this.THRESHOLD_2) + { + warningStatus = Result.WARNING_STATUS_HIGH_RISK; + } + if(TMDD5C >= this.THRESHOLD_3) + { + warningStatus = Result.WARNING_STATUS_NO_WARNING; + } + result.setWarningStatus(warningStatus); + retVal.add(result); + // Moving on... + cal.setTime(currentDate); + cal.add(Calendar.DATE, 1); + currentDate = cal.getTime();*/ + } + + return null; + //return retVal; + } + + @Override + public ModelId getModelId() { + return DayDegreeModel.MODEL_ID; + } + + @Override + public String getModelName() { + return this.getModelName(Model.DEFAULT_LANGUAGE); + } + + @Override + public String getModelName(String language) { + return this.getText("name", language); + } + + @Override + public String getLicense() { + return "/*\n" + + " * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. \n" + + " * \n" + + " * This file is part of PsilaRosaeTempModel.\n" + + " * This program is free software: you can redistribute it and/or modify\n" + + " * it under the terms of the GNU Affero General Public License as published by\n" + + " * the Free Software Foundation, either version 3 of the License, or\n" + + " * (at your option) any later version.\n" + + " *\n" + + " * This program is distributed in the hope that it will be useful,\n" + + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + + " * GNU Affero General Public License for more details.\n" + + " *\n" + + " * You should have received a copy of the GNU Affero General Public License\n" + + " * along with this program. If not, see <https://www.gnu.org/licenses/>.\n" + + " */"; + } + + @Override + public String getCopyright() { + return "(c) 2015-2021 NIBIO (http://www.nibio.no/). Contact: post@nibio.no"; + } + + @Override + public String getModelDescription() { + return this.getModelDescription(Model.DEFAULT_LANGUAGE); + } + + @Override + public String getModelDescription(String language) { + try + { + return this.modelUtil.getTextWithBase64EncodedImages(this.getText("description", language), this.getClass()); + } + catch(IOException ex) + { + return this.getText("description", language); + } + } + + + @Override + public String getWarningStatusInterpretation() { + return this.getWarningStatusInterpretation(Model.DEFAULT_LANGUAGE); + } + + @Override + public String getWarningStatusInterpretation(String language) { + return this.getText("statusInterpretation", language); + } + + @Override + public String getModelUsage() { + return this.getModelUsage(Model.DEFAULT_LANGUAGE); + } + + @Override + public String getModelUsage(String language) { + return this.getText("usage", language); + } + + @Override + public String getSampleConfig() { + return "{\n" + + "\t\"loginInfo\":{\n" + + "\t\t\"username\":\"example\",\n" + + "\t\t\"password\":\"example\"\n" + + "\t},\n" + + "\t\"modelId\":\"" + MODEL_ID.toString() + "\",\n" + + "\t\"configParameters\":{\n" + + "\t\t\"timeZone\": \"Europe/Oslo\",\n" + + "\t\t\"observations\":[\n" + + "\t\t{\n" + + "\t\t\t\t\"timeMeasured\": \"2015-01-01T00:00:00+02:00\",\n" + + "\t\t\t\t\"elementMeasurementTypeId\":\"TM\",\n" + + "\t\t\t\t\"logIntervalId\":2,\n" + + "\t\t\t\t\"value\":-1.1\n" + + "\t\t}\n" + + "}\n"; + } + + @Override + public void setConfiguration(ModelConfiguration config) throws ConfigValidationException { + // Initialize the weather data collections + this.TM = new ArrayList<>(); + + // Init data matrix + this.dataMatrix = new DataMatrix(); + + // Setting timezone + this.timeZone = TimeZone.getTimeZone((String) config.getConfigParameter("timeZone")); + //System.out.println("TimeZone=" + this.timeZone); + + // Importing weather data, creating collections + // Can accept both hourly and daily data + WeatherUtil wUtil = new WeatherUtil(); + + List<WeatherObservation> observations = modelUtil.extractWeatherObservationList(config.getConfigParameter("observations")); + if(observations == null || observations.isEmpty()) + { + throw new ConfigValidationException("Please provide weather data."); + } + for(WeatherObservation o:observations) + { + switch(o.getElementMeasurementTypeId()) + { + case WeatherElements.TEMPERATURE_MEAN: + if(o.getLogIntervalId().equals(WeatherObservation.LOG_INTERVAL_ID_1H)) + { + this.TM.add(o); + }else { + o.setTimeMeasured(wUtil.pragmaticAdjustmentToMidnight(o.getTimeMeasured(), timeZone)); + this.dataMatrix.setParamValueForDate(o.getTimeMeasured(), DataMatrix.TMD, o); + }break; + default: + // Keep calm and continue importing data + break; + } + } + + // If we've received hourly weather data, create and store daily values + // Air temperature + if(dataMatrix.getFirstDateWithParameterValue(DataMatrix.TMD) == null) + { + try { + List<WeatherObservation> dailyTemperatures = new WeatherUtil().getAggregatedDailyValues( + this.TM, + this.timeZone, + 15, + WeatherUtil.AGGREGATION_TYPE_AVERAGE, + 0, + true); + for(WeatherObservation obs:dailyTemperatures) + { + this.dataMatrix.setParamValueForDate(obs.getTimeMeasured(), DataMatrix.TMD, obs); + } + } catch (WeatherObservationListException | InvalidAggregationTypeException ex) { + throw new ConfigValidationException(ex.getMessage()); + } + } + + //System.out.println("DataMatrix"); + //System.out.println(this.dataMatrix.toString()); + } + + /** + * Operates on the datamatrix + * @param inputParameterName the parameter to sum + * @param outputParameterName the result + */ + private void calculateTemperatureSum(String inputParameterName, String outputParameterName) throws ModelExcecutionException { + Date today = this.dataMatrix.getFirstDateWithParameterValue(inputParameterName); + Date lastDate = this.dataMatrix.getLastDateWithParameterValue(inputParameterName); + Calendar cal = Calendar.getInstance(this.timeZone); + + Double sum = 0.0; + while(today.compareTo(lastDate) <= 0) + { + WeatherObservation todayTemp = (WeatherObservation)this.dataMatrix.getParamValueForDate(today, inputParameterName); + if(todayTemp == null) + { + throw new ModelExcecutionException("Missing weather data at " + today + ": " + inputParameterName); + } + //System.out.println("today=" + today + ",todayTemp=" + todayTemp); + Double dailyContribution = Math.max(0.0, todayTemp.getValue() - this.dayDegreeBaseTemp); + this.dataMatrix.setParamDoubleValueForDate(today, DataMatrix.TMD0C, dailyContribution); + sum += dailyContribution; + this.dataMatrix.setParamDoubleValueForDate(today, outputParameterName, sum); + cal.setTime(today); + cal.add(Calendar.DATE, 1); + today = cal.getTime(); + } + } + +} +