ClimaticDailyData.java
/*
* This file is part of Indicators.
*
* Indicators is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Indicators 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Indicators. If not, see <https://www.gnu.org/licenses/>.
*/
package fr.inrae.agroclim.indicators.model.data.climate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import fr.inrae.agroclim.indicators.model.TimeScale;
import fr.inrae.agroclim.indicators.model.data.DailyData;
import fr.inrae.agroclim.indicators.model.data.Variable;
import fr.inrae.agroclim.indicators.model.data.Variable.Type;
import fr.inrae.agroclim.indicators.resources.Messages;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
/**
* Class to handle reading climatic daily data.
*
* @author $Author$
*/
public final class ClimaticDailyData extends DailyData {
/**
* UUID for Serializable.
*/
private static final long serialVersionUID = 4872847709393688042L;
/**
* @param timescale related timescale
* @return Names of all columns, according to timescale.
*/
public static List<String> getAllColumnNames(@NonNull final TimeScale timescale) {
switch (timescale) {
case DAILY:
return Arrays.asList("year", "month", "day", "tmin", "tmax", "tmean", "radiation", "rain", "wind", "etp",
"rh", "soilwatercontent");
case HOURLY:
return Arrays.asList("year", "month", "day", "hour", "th", "radiation", "rain", "wind", "etp", "rh");
default:
throw new UnsupportedOperationException("Not implemented: " + timescale);
}
}
/**
* @param timescale related timescale
* @return Names of all columns, according to timescale.
*/
public static List<String> getOptionalColumnNames(final TimeScale timescale) {
switch (timescale) {
case DAILY:
return Arrays.asList("rh", "soilwatercontent");
case HOURLY:
return Arrays.asList("rh");
default:
throw new UnsupportedOperationException("Not implemented: " + timescale);
}
}
/**
* @param timescale related timescale
* @return Names of required columns, according to timescale, used by GUI.
*/
public static List<String> getRequiredColumnNames(final TimeScale timescale) {
switch (timescale) {
case DAILY:
return Arrays.asList("year", "month", "day");
case HOURLY:
return Arrays.asList("year", "month", "hour");
default:
throw new UnsupportedOperationException("Not implemented: " + timescale);
}
}
/**
* Errors for the data.
*/
private final List<String> errors = new ArrayList<>();
/**
* Compute ETP from climatic daily data.
*/
@Getter
@Setter
private EtpCalculator etpCalculator;
/**
* Related time scale.
*/
@Setter
private TimeScale timescale;
/**
* Warnings for the data.
*/
private final List<String> warnings = new ArrayList<>();
/**
* Constructor.
*/
public ClimaticDailyData() {
//
}
/**
* Copy constructor.
*
* @param data instance to copy
*/
public ClimaticDailyData(final ClimaticDailyData data) {
super(data);
this.timescale = data.timescale;
this.etpCalculator = data.etpCalculator;
}
@Override
public void check(final int line, final String path) {
if (getTmin() != null && getTmax() != null && getTmin() > getTmax()) {
warnings.add(Messages.format("warning.tmax.inferiorto.tmin", path, line));
}
final double rhMin = 0;
final double rhMax = 100;
if (getRh() != null && (getRh() < rhMin || getRh() > rhMax)) {
warnings.add(Messages.format("error.rh.outofrange", path, line));
}
if (timescale == TimeScale.DAILY && getRawValue(Variable.ETP) == null) {
boolean missing = false;
for (final Variable variable : etpCalculator.getVariables()) {
if (getRawValue(variable) == null) {
missing = true;
}
}
if (missing) {
warnings.add(Messages.format("warning.missing", path, line, "ETP"));
}
}
for (final Variable variable : Variable.getByTimeScaleAndType(timescale, Type.CLIMATIC)) {
if (variable != Variable.ETP && getValue(variable) == null) {
warnings.add(Messages.format("warning.missing", path, line, variable.getName()));
}
}
if (getMonth() == null || getMonth() != null && getMonth() == 0) {
errors.add(Messages.format("error.month.null", path, line));
}
if (getDay() == null || getDay() != null && getDay() == 0) {
errors.add(Messages.format("error.day.null", path, line));
}
}
@Override
public ClimaticDailyData clone() throws CloneNotSupportedException {
final ClimaticDailyData clone = (ClimaticDailyData) super.clone();
if (etpCalculator != null) {
clone.etpCalculator = etpCalculator.clone();
}
clone.errors.addAll(errors);
clone.warnings.addAll(warnings);
return clone;
}
@Override
public List<String> getErrors() {
return errors;
}
/**
* @return stored ETP value or compute it.
*/
public Double getEtp() {
Double etp = getRawValue(Variable.ETP);
if (etp == null && etpCalculator != null) {
try {
etp = etpCalculator.compute(this);
setEtp(etp);
} catch (IllegalArgumentException e) {
etp = null;
}
}
return etp;
}
/**
* @return Global radiation [W/m²].
*/
public Double getRadiation() {
return getRawValue(Variable.RADIATION);
}
/**
* @return Rain precipitation [mm/d].
*/
public Double getRain() {
return getRawValue(Variable.RAIN);
}
/**
* @return relative humidity (%)
*/
public Double getRh() {
return getRawValue(Variable.RH);
}
/**
* @return Soil water content [% mass]
*/
public Double getSoilwatercontent() {
return getRawValue(Variable.SOILWATERCONTENT);
}
/**
* @return Instantaneous hourly air temperature [°C].
*/
public Double getTh() {
return getRawValue(Variable.TH);
}
/**
* @return Maximal air temperature [°C]
*/
public Double getTmax() {
return getRawValue(Variable.TMAX);
}
/**
* @return Average air temperature [°C]
*/
public Double getTmean() {
return getRawValue(Variable.TMEAN);
}
/**
* @return Minimal air temperature [°C]
*/
public Double getTmin() {
return getRawValue(Variable.TMIN);
}
@Override
public Double getValue(final Variable variable) {
if (variable == Variable.ETP) {
return getEtp();
}
return super.getRawValue(variable);
}
@Override
public List<String> getWarnings() {
return warnings;
}
/**
* @return Wind speed [m/s]
*/
public Double getWind() {
return getValue(Variable.WIND);
}
/**
* @param value Evapotranspiration [mm/d].
*/
public void setEtp(final Double value) {
setValue(Variable.ETP, value);
}
/**
* @param value Global radiation [W/m²]
*/
public void setRadiation(final Double value) {
setValue(Variable.RADIATION, value);
}
/**
* @param value Rain precipitation [mm]
*/
public void setRain(final Double value) {
setValue(Variable.RAIN, value);
}
/**
* @param value Relative humidity.
*/
public void setRh(final Double value) {
setValue(Variable.RH, value);
}
/**
* @param value Soil water content [% mass]
*/
public void setSoilwatercontent(final Double value) {
setValue(Variable.SOILWATERCONTENT, value);
}
/**
* @param value Instantaneous hourly air temperature [°C]
*/
public void setTh(final Double value) {
setValue(Variable.TH, value);
}
/**
* @param value Maximal air temperature [°C]
*/
public void setTmax(final Double value) {
setValue(Variable.TMAX, value);
}
/**
* @param value Average air temperature [°C]
*/
public void setTmean(final Double value) {
setValue(Variable.TMEAN, value);
}
/**
* @param value Minimal air temperature [°C]
*/
public void setTmin(final Double value) {
setValue(Variable.TMIN, value);
}
/**
* @param value Wind speed [m/s]
*/
public void setWind(final Double value) {
setValue(Variable.WIND, value);
}
@Override
public String toString() {
final StringJoiner sj = new StringJoiner(", ");
for (final Variable variable : Variable.values()) {
sj.add(variable.name() + "=" + getRawValue(variable));
}
return "ClimaticDailyData [year=" + getYear() + ", month=" + getMonth()
+ ", day=" + getDay() + ", hour=" + getHour() + ", " + sj.toString() + "]";
}
}