View Javadoc
1   /**
2    * This file is part of Indicators.
3    *
4    * Indicators is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * Indicators is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with Indicators. If not, see <https://www.gnu.org/licenses/>.
16   */
17  package fr.inrae.agroclim.indicators.model;
18  
19  import java.io.Serializable;
20  import java.nio.file.Path;
21  import java.nio.file.Paths;
22  import java.time.LocalDateTime;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Objects;
27  
28  import fr.inrae.agroclim.indicators.exception.IndicatorsException;
29  import fr.inrae.agroclim.indicators.model.criteria.ComparisonCriteria;
30  import fr.inrae.agroclim.indicators.model.criteria.CompositeCriteria;
31  import fr.inrae.agroclim.indicators.model.criteria.FormulaCriteria;
32  import fr.inrae.agroclim.indicators.model.criteria.LogicalOperator;
33  import fr.inrae.agroclim.indicators.model.criteria.NoCriteria;
34  import fr.inrae.agroclim.indicators.model.criteria.RelationalOperator;
35  import fr.inrae.agroclim.indicators.model.criteria.SimpleCriteria;
36  import fr.inrae.agroclim.indicators.model.data.Variable;
37  import fr.inrae.agroclim.indicators.model.data.climate.ClimateFileLoader;
38  import fr.inrae.agroclim.indicators.model.data.climate.ClimateLoaderProxy;
39  import fr.inrae.agroclim.indicators.model.data.phenology.PhenologyCalculator;
40  import fr.inrae.agroclim.indicators.model.data.phenology.PhenologyFileLoader;
41  import fr.inrae.agroclim.indicators.model.data.phenology.PhenologyLoaderProxy;
42  import fr.inrae.agroclim.indicators.model.data.soil.SoilLoaderProxy;
43  import fr.inrae.agroclim.indicators.model.function.aggregation.AggregationFunction;
44  import fr.inrae.agroclim.indicators.model.function.aggregation.JEXLFunction;
45  import fr.inrae.agroclim.indicators.model.function.normalization.Exponential;
46  import fr.inrae.agroclim.indicators.model.function.normalization.Linear;
47  import fr.inrae.agroclim.indicators.model.function.normalization.MultiLinear;
48  import fr.inrae.agroclim.indicators.model.function.normalization.Normal;
49  import fr.inrae.agroclim.indicators.model.function.normalization.NormalizationFunction;
50  import fr.inrae.agroclim.indicators.model.function.normalization.Sigmoid;
51  import fr.inrae.agroclim.indicators.model.indicator.Average;
52  import fr.inrae.agroclim.indicators.model.indicator.AverageOfDiff;
53  import fr.inrae.agroclim.indicators.model.indicator.CompositeIndicator;
54  import fr.inrae.agroclim.indicators.model.indicator.DayOfYear;
55  import fr.inrae.agroclim.indicators.model.indicator.DiffOfSum;
56  import fr.inrae.agroclim.indicators.model.indicator.Formula;
57  import fr.inrae.agroclim.indicators.model.indicator.Indicator;
58  import fr.inrae.agroclim.indicators.model.indicator.Max;
59  import fr.inrae.agroclim.indicators.model.indicator.MaxWaveLength;
60  import fr.inrae.agroclim.indicators.model.indicator.Min;
61  import fr.inrae.agroclim.indicators.model.indicator.NumberOfDays;
62  import fr.inrae.agroclim.indicators.model.indicator.NumberOfWaves;
63  import fr.inrae.agroclim.indicators.model.indicator.PhaseLength;
64  import fr.inrae.agroclim.indicators.model.indicator.PotentialSowingDaysFrequency;
65  import fr.inrae.agroclim.indicators.model.indicator.Quotient;
66  import fr.inrae.agroclim.indicators.model.indicator.SimpleIndicator;
67  import fr.inrae.agroclim.indicators.model.indicator.Sum;
68  import fr.inrae.agroclim.indicators.model.indicator.Tamm;
69  import jakarta.xml.bind.annotation.XmlAccessType;
70  import jakarta.xml.bind.annotation.XmlAccessorType;
71  import jakarta.xml.bind.annotation.XmlAttribute;
72  import jakarta.xml.bind.annotation.XmlElement;
73  import jakarta.xml.bind.annotation.XmlElementWrapper;
74  import jakarta.xml.bind.annotation.XmlRootElement;
75  import jakarta.xml.bind.annotation.XmlTransient;
76  import jakarta.xml.bind.annotation.XmlType;
77  import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
78  import lombok.EqualsAndHashCode;
79  import lombok.Getter;
80  import lombok.Setter;
81  import lombok.ToString;
82  import lombok.extern.log4j.Log4j2;
83  
84  /**
85   * Settings from XML.
86   *
87   * Last change $Date$
88   *
89   * @author $Author$
90   * @version $Revision$
91   */
92  @XmlRootElement
93  @XmlAccessorType(XmlAccessType.FIELD)
94  @XmlType(propOrder = {"climateLoader", "notes", "phenologyLoader", "soilLoader",
95          "soilPhenologyCalculator", "name", "type", "timescale", "evaluation"})
96  @EqualsAndHashCode(
97          callSuper = false,
98          of = {"climateLoader", "evaluation", "filePath", "knowledge", "name",
99                  "phenologyLoader", "soilLoader", "soilPhenologyCalculator"})
100 @Log4j2
101 @ToString
102 public final class EvaluationSettings implements Cloneable, Serializable {
103 
104     /**
105      * Classes needed to load evaluation-settings.xml with XMLUtil.
106      */
107     public static final Class<?>[] CLASSES_FOR_JAXB = new Class<?>[] {
108         EvaluationSettings.class, EvaluationType.class, Knowledge.class, Note.class,
109         PhaseLength.class, Variable.class, TimeScale.class,
110         /*- Climate */
111         ClimateLoaderProxy.class, ClimateFileLoader.class,
112         /*- Phenology */
113         PhenologyLoaderProxy.class, PhenologyFileLoader.class,
114         /*- Soil */
115         /*- Indicators */
116         Average.class, AverageOfDiff.class, CompositeIndicator.class,
117         DayOfYear.class, DiffOfSum.class, Formula.class, Indicator.class, Max.class, MaxWaveLength.class, Min.class,
118         Normal.class, NumberOfDays.class, NumberOfWaves.class,
119         PotentialSowingDaysFrequency.class, Quotient.class,
120         SimpleIndicator.class, Sum.class, Tamm.class,
121         /*- Criteria */
122         ComparisonCriteria.class, CompositeCriteria.class, ExpressionParameter.class, FormulaCriteria.class,
123         LogicalOperator.class, NoCriteria.class, Parameter.class, RelationalOperator.class, SimpleCriteria.class,
124         /*- Normalisation */
125         AggregationFunction.class, Exponential.class, JEXLFunction.class,
126         Linear.class, MultiLinear.class, NormalizationFunction.class, Sigmoid.class
127     };
128 
129     /**
130      * UUID for Serializable.
131      */
132     private static final long serialVersionUID = 3308126437081517192L;
133 
134     /**
135      * Climate.
136      */
137     @XmlElement(name = "climate")
138     @Getter
139     private ClimateLoaderProxy climateLoader;
140 
141     /**
142      * The composite indicator.
143      */
144     @XmlElement(name = "compositeIndicator")
145     @Getter
146     @Setter
147     private CompositeIndicator evaluation;
148 
149     /**
150      * evaluation-settings.xml file path.
151      */
152     @XmlTransient
153     @Getter
154     private String filePath;
155 
156     /**
157      * Knowledge XML.
158      */
159     @Getter
160     private transient Knowledge knowledge;
161 
162     /**
163      * Evaluation name.
164      */
165     @XmlElement
166     @Getter
167     @Setter
168     private String name;
169 
170     /**
171      * Phenology definition.
172      */
173     @XmlElement(name = "phenology")
174     @Getter
175     @Setter
176     private PhenologyLoaderProxy phenologyLoader;
177 
178     /**
179      * The proxy with decides which loader to use.
180      */
181     @XmlElement(name = "soil")
182     @Getter
183     @Setter
184     private SoilLoaderProxy soilLoader;
185 
186     /**
187      * The phenology calculator with variety parameters add values to compute 4
188      * stages for soil calculator.
189      */
190     @XmlElement(name = "soilPhenologyCalculator")
191     @Getter
192     @Setter
193     private PhenologyCalculator soilPhenologyCalculator;
194 
195     /**
196      * Timescale of indicators.
197      */
198     @Getter
199     @Setter
200     @XmlAttribute
201     private TimeScale timescale = TimeScale.DAILY;
202 
203     /**
204      * Date of last modification.
205      */
206     @Getter
207     @Setter
208     @XmlAttribute(name = "timestamp", required = false)
209     @XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
210     private LocalDateTime timestamp;
211 
212     /**
213      * Evaluation type.
214      */
215     @Getter
216     @Setter
217     @XmlElement(name = "type")
218     private EvaluationType type = EvaluationType.WITH_AGGREGATION;
219 
220     /**
221      * Version of Indicators.
222      */
223     @Getter
224     @Setter
225     @XmlAttribute(required = false)
226     private String version = "";
227     /**
228      * Notes library for indicators.
229      */
230     @XmlElementWrapper(name = "notes")
231     @XmlElement(name = "note")
232     @Getter
233     @Setter
234     private List<Note> notes;
235 
236     /**
237      * Constructor.
238      */
239     public EvaluationSettings() {
240         evaluation = new Evaluation();
241     }
242 
243     @Override
244     public EvaluationSettings clone() throws CloneNotSupportedException {
245         final EvaluationSettings clone = new EvaluationSettings();
246         if (climateLoader != null) {
247             clone.climateLoader = climateLoader.clone();
248         }
249         if (evaluation != null) {
250             clone.evaluation = evaluation.clone();
251         }
252         clone.filePath = filePath;
253         if (knowledge != null) {
254             clone.knowledge = knowledge.clone();
255         }
256         clone.name = name;
257         if (phenologyLoader != null) {
258             clone.phenologyLoader = phenologyLoader.clone();
259         }
260         if (soilLoader != null) {
261             clone.soilLoader = soilLoader.clone();
262         }
263         return clone;
264     }
265 
266     /**
267      * @return errors of configuration.
268      */
269     public Map<String, String> getConfigurationErrors() {
270         final Map<String, String> errors = new HashMap<>();
271         if (getClimateLoader() == null) {
272             errors.put("evaluationSettings.climate",
273                     "error.evaluation.climate.null");
274         } else if (getClimateLoader().getConfigurationErrors() != null) {
275             errors.putAll(getClimateLoader().getConfigurationErrors());
276         }
277         if (getSoilLoader() != null
278                 && getSoilLoader().getConfigurationErrors() != null) {
279             errors.putAll(getSoilLoader().getConfigurationErrors());
280         }
281         if (getPhenologyLoader() == null) {
282             errors.put("evaluationSettings.phenology", "error.evaluation.phenology.null");
283         } else if (getPhenologyLoader().getConfigurationErrors() != null) {
284             errors.putAll(getPhenologyLoader().getConfigurationErrors());
285         }
286         return errors;
287     }
288 
289     /**
290      * Load Knowledge.
291      * @throws IndicatorsException while loading Knowledge
292      */
293     public void initializeKnowledge() throws IndicatorsException {
294         knowledge = Knowledge.load(timescale);
295     }
296 
297     /**
298      * @param value climate resource
299      */
300     public void setClimate(final ClimateLoaderProxy value) {
301         this.climateLoader = value;
302     }
303 
304     /**
305      * Set evaluation-settings.xml file path.
306      *
307      * @param path evaluation-settings.xml file path.
308      */
309     public void setFilePath(final String path) {
310         if (!Objects.equals(filePath, path)) {
311             this.filePath = path;
312             final Path baseDir = Paths.get(path).getParent();
313             if (climateLoader != null && climateLoader.getFile() != null) {
314                 climateLoader.getFile().setBaseDirectory(baseDir);
315             }
316             if (phenologyLoader != null && phenologyLoader.getFile() != null) {
317                 phenologyLoader.getFile().setBaseDirectory(baseDir);
318             }
319         }
320     }
321 }