EvaluationSettings.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;
import java.io.Serializable;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.model.criteria.ComparisonCriteria;
import fr.inrae.agroclim.indicators.model.criteria.CompositeCriteria;
import fr.inrae.agroclim.indicators.model.criteria.FormulaCriteria;
import fr.inrae.agroclim.indicators.model.criteria.LogicalOperator;
import fr.inrae.agroclim.indicators.model.criteria.NoCriteria;
import fr.inrae.agroclim.indicators.model.criteria.RelationalOperator;
import fr.inrae.agroclim.indicators.model.criteria.SimpleCriteria;
import fr.inrae.agroclim.indicators.model.data.Variable;
import fr.inrae.agroclim.indicators.model.data.climate.ClimateFileLoader;
import fr.inrae.agroclim.indicators.model.data.climate.ClimateLoaderProxy;
import fr.inrae.agroclim.indicators.model.data.phenology.PhenologyCalculator;
import fr.inrae.agroclim.indicators.model.data.phenology.PhenologyFileLoader;
import fr.inrae.agroclim.indicators.model.data.phenology.PhenologyLoaderProxy;
import fr.inrae.agroclim.indicators.model.data.soil.SoilLoaderProxy;
import fr.inrae.agroclim.indicators.model.function.aggregation.AggregationFunction;
import fr.inrae.agroclim.indicators.model.function.aggregation.JEXLFunction;
import fr.inrae.agroclim.indicators.model.function.normalization.Exponential;
import fr.inrae.agroclim.indicators.model.function.normalization.Linear;
import fr.inrae.agroclim.indicators.model.function.normalization.MultiLinear;
import fr.inrae.agroclim.indicators.model.function.normalization.Normal;
import fr.inrae.agroclim.indicators.model.function.normalization.NormalizationFunction;
import fr.inrae.agroclim.indicators.model.function.normalization.Sigmoid;
import fr.inrae.agroclim.indicators.model.indicator.Average;
import fr.inrae.agroclim.indicators.model.indicator.AverageOfDiff;
import fr.inrae.agroclim.indicators.model.indicator.CompositeIndicator;
import fr.inrae.agroclim.indicators.model.indicator.DayOfYear;
import fr.inrae.agroclim.indicators.model.indicator.DiffOfSum;
import fr.inrae.agroclim.indicators.model.indicator.Formula;
import fr.inrae.agroclim.indicators.model.indicator.Indicator;
import fr.inrae.agroclim.indicators.model.indicator.Max;
import fr.inrae.agroclim.indicators.model.indicator.MaxWaveLength;
import fr.inrae.agroclim.indicators.model.indicator.Min;
import fr.inrae.agroclim.indicators.model.indicator.NumberOfDays;
import fr.inrae.agroclim.indicators.model.indicator.NumberOfWaves;
import fr.inrae.agroclim.indicators.model.indicator.PhaseLength;
import fr.inrae.agroclim.indicators.model.indicator.PotentialSowingDaysFrequency;
import fr.inrae.agroclim.indicators.model.indicator.Quotient;
import fr.inrae.agroclim.indicators.model.indicator.SimpleIndicator;
import fr.inrae.agroclim.indicators.model.indicator.Sum;
import fr.inrae.agroclim.indicators.model.indicator.Tamm;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
import jakarta.xml.bind.annotation.XmlType;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
/**
* Settings from XML.
*
* Last change $Date$
*
* @author $Author$
* @version $Revision$
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {"climateLoader", "notes", "phenologyLoader", "soilLoader",
"soilPhenologyCalculator", "name", "type", "timescale", "evaluation"})
@EqualsAndHashCode(
callSuper = false,
of = {"climateLoader", "evaluation", "filePath", "knowledge", "name",
"phenologyLoader", "soilLoader", "soilPhenologyCalculator"})
@Log4j2
@ToString
public final class EvaluationSettings implements Cloneable, Serializable {
/**
* Classes needed to load evaluation-settings.xml with XMLUtil.
*/
public static final Class<?>[] CLASSES_FOR_JAXB = new Class<?>[] {
EvaluationSettings.class, EvaluationType.class, Knowledge.class, Note.class,
PhaseLength.class, Variable.class, TimeScale.class,
/*- Climate */
ClimateLoaderProxy.class, ClimateFileLoader.class,
/*- Phenology */
PhenologyLoaderProxy.class, PhenologyFileLoader.class,
/*- Soil */
/*- Indicators */
Average.class, AverageOfDiff.class, CompositeIndicator.class,
DayOfYear.class, DiffOfSum.class, Formula.class, Indicator.class, Max.class, MaxWaveLength.class, Min.class,
Normal.class, NumberOfDays.class, NumberOfWaves.class,
PotentialSowingDaysFrequency.class, Quotient.class,
SimpleIndicator.class, Sum.class, Tamm.class,
/*- Criteria */
ComparisonCriteria.class, CompositeCriteria.class, ExpressionParameter.class, FormulaCriteria.class,
LogicalOperator.class, NoCriteria.class, Parameter.class, RelationalOperator.class, SimpleCriteria.class,
/*- Normalisation */
AggregationFunction.class, Exponential.class, JEXLFunction.class,
Linear.class, MultiLinear.class, NormalizationFunction.class, Sigmoid.class
};
/**
* UUID for Serializable.
*/
private static final long serialVersionUID = 3308126437081517192L;
/**
* Climate.
*/
@XmlElement(name = "climate")
@Getter
private ClimateLoaderProxy climateLoader;
/**
* The composite indicator.
*/
@XmlElement(name = "compositeIndicator")
@Getter
@Setter
private CompositeIndicator evaluation;
/**
* evaluation-settings.xml file path.
*/
@XmlTransient
@Getter
private String filePath;
/**
* Knowledge XML.
*/
@Getter
private transient Knowledge knowledge;
/**
* Evaluation name.
*/
@XmlElement
@Getter
@Setter
private String name;
/**
* Phenology definition.
*/
@XmlElement(name = "phenology")
@Getter
@Setter
private PhenologyLoaderProxy phenologyLoader;
/**
* The proxy with decides which loader to use.
*/
@XmlElement(name = "soil")
@Getter
@Setter
private SoilLoaderProxy soilLoader;
/**
* The phenology calculator with variety parameters add values to compute 4
* stages for soil calculator.
*/
@XmlElement(name = "soilPhenologyCalculator")
@Getter
@Setter
private PhenologyCalculator soilPhenologyCalculator;
/**
* Timescale of indicators.
*/
@Getter
@Setter
@XmlAttribute
private TimeScale timescale = TimeScale.DAILY;
/**
* Date of last modification.
*/
@Getter
@Setter
@XmlAttribute(name = "timestamp", required = false)
@XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
private LocalDateTime timestamp;
/**
* Evaluation type.
*/
@Getter
@Setter
@XmlElement(name = "type")
private EvaluationType type = EvaluationType.WITH_AGGREGATION;
/**
* Version of Indicators.
*/
@Getter
@Setter
@XmlAttribute(required = false)
private String version = "";
/**
* Notes library for indicators.
*/
@XmlElementWrapper(name = "notes")
@XmlElement(name = "note")
@Getter
@Setter
private List<Note> notes;
/**
* Constructor.
*/
public EvaluationSettings() {
evaluation = new Evaluation();
}
@Override
public EvaluationSettings clone() throws CloneNotSupportedException {
final EvaluationSettings clone = new EvaluationSettings();
if (climateLoader != null) {
clone.climateLoader = climateLoader.clone();
}
if (evaluation != null) {
clone.evaluation = evaluation.clone();
}
clone.filePath = filePath;
if (knowledge != null) {
clone.knowledge = knowledge.clone();
}
clone.name = name;
if (phenologyLoader != null) {
clone.phenologyLoader = phenologyLoader.clone();
}
if (soilLoader != null) {
clone.soilLoader = soilLoader.clone();
}
return clone;
}
/**
* @return errors of configuration.
*/
public Map<String, String> getConfigurationErrors() {
final Map<String, String> errors = new HashMap<>();
if (getClimateLoader() == null) {
errors.put("evaluationSettings.climate",
"error.evaluation.climate.null");
} else if (getClimateLoader().getConfigurationErrors() != null) {
errors.putAll(getClimateLoader().getConfigurationErrors());
}
if (getSoilLoader() != null
&& getSoilLoader().getConfigurationErrors() != null) {
errors.putAll(getSoilLoader().getConfigurationErrors());
}
if (getPhenologyLoader() == null) {
errors.put("evaluationSettings.phenology", "error.evaluation.phenology.null");
} else if (getPhenologyLoader().getConfigurationErrors() != null) {
errors.putAll(getPhenologyLoader().getConfigurationErrors());
}
return errors;
}
/**
* Load Knowledge.
* @throws IndicatorsException while loading Knowledge
*/
public void initializeKnowledge() throws IndicatorsException {
knowledge = Knowledge.load(timescale);
}
/**
* @param value climate resource
*/
public void setClimate(final ClimateLoaderProxy value) {
this.climateLoader = value;
}
/**
* Set evaluation-settings.xml file path.
*
* @param path evaluation-settings.xml file path.
*/
public void setFilePath(final String path) {
if (!Objects.equals(filePath, path)) {
this.filePath = path;
final Path baseDir = Paths.get(path).getParent();
if (climateLoader != null && climateLoader.getFile() != null) {
climateLoader.getFile().setBaseDirectory(baseDir);
}
if (phenologyLoader != null && phenologyLoader.getFile() != null) {
phenologyLoader.getFile().setBaseDirectory(baseDir);
}
}
}
}