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.criteria;
18  
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Objects;
23  import java.util.Optional;
24  
25  import fr.inrae.agroclim.indicators.exception.IndicatorsException;
26  import fr.inrae.agroclim.indicators.model.Parameter;
27  import fr.inrae.agroclim.indicators.model.data.DailyData;
28  import fr.inrae.agroclim.indicators.model.data.Variable;
29  import fr.inrae.agroclim.indicators.model.data.climate.ClimaticDailyData;
30  import fr.inrae.agroclim.indicators.util.Doublet;
31  import jakarta.xml.bind.annotation.XmlElement;
32  import jakarta.xml.bind.annotation.XmlRootElement;
33  import jakarta.xml.bind.annotation.XmlTransient;
34  import jakarta.xml.bind.annotation.XmlType;
35  import lombok.EqualsAndHashCode;
36  import lombok.Getter;
37  import lombok.Setter;
38  import lombok.ToString;
39  import lombok.extern.log4j.Log4j2;
40  
41  /**
42   * Criteria to compare value with threshold or to define variable to use in
43   * aggregation indicator (eg.: Sum).
44   *
45   * Last changed : $Date$
46   *
47   * @author jcufi
48   * @author $Author$
49   * @version $Revision$
50   */
51  @XmlRootElement
52  @XmlType(propOrder = {"inferiorToThreshold", "strict", "operator", "threshold", "noThreshold"})
53  @ToString
54  @Log4j2
55  @EqualsAndHashCode(callSuper = true, of = {"noThreshold", "operator", "threshold"})
56  public final class SimpleCriteria extends VariableCriteria {
57      /**
58       * UUID for Serializable.
59       */
60      private static final long serialVersionUID = -4284278102762199667L;
61  
62      /**
63       * Tag name.
64       */
65      private static final String THRESHOLD = "threshold";
66  
67      /**
68       * true for comparison inferior or inferior or equal, false for superior or superior or equal.
69       */
70      @XmlTransient
71      private boolean inferiorToThreshold = true;
72  
73      /**
74       * No threshold, to simply use the value (eg.: in sum).
75       */
76      @XmlElement
77      @Getter
78      @Setter
79      private boolean noThreshold = false;
80  
81      /**
82       * The relational operator to compare variable and threshold.
83       */
84      @XmlElement
85      @Getter
86      @Setter
87      private RelationalOperator operator = RelationalOperator.LT;
88  
89      /**
90       * Comparison is strictly inferior or superior.
91       */
92      @XmlTransient
93      private boolean strict = true;
94  
95      /**
96       * Threshold value.
97       */
98      @XmlElement
99      @Getter
100     private double threshold;
101 
102     /**
103      * Criteria.
104      */
105     public SimpleCriteria() {
106         super();
107     }
108 
109     /**
110      * Constructor.
111      *
112      * @param variable
113      *            variable name
114      * @param op
115      *            operator for comparison
116      * @param thr
117      *            threshold value
118      */
119     public SimpleCriteria(final String variable, final RelationalOperator op, final double thr) {
120         setOperator(op);
121         setVariable(Variable.getByName(variable));
122         setThreshold(thr);
123     }
124 
125     @Override
126     public SimpleCriteria clone() {
127         final SimpleCriteria clone = new SimpleCriteria();
128         clone.threshold = threshold;
129         clone.setVariable(getVariable());
130         clone.inferiorToThreshold = inferiorToThreshold;
131         clone.strict = strict;
132         clone.noThreshold = noThreshold;
133         clone.operator = operator;
134         if (getParameters() != null) {
135             clone.setParameters(getParameters());
136         }
137         return clone;
138     }
139 
140     @Override
141     public boolean eval(final DailyData dailydata) throws IndicatorsException {
142         if (dailydata == null) {
143             return false;
144         }
145         if (isNoThreshold()) {
146             return true;
147         }
148         final double val = getValueOf(dailydata);
149         return operator.eval(val, getThreshold());
150     }
151 
152     /**
153      * @param data
154      *            climatic data
155      * @return formula
156      * @throws IndicatorsException
157      *             exception while getting data
158      */
159     public String getFormula(final ClimaticDailyData data) throws IndicatorsException {
160         final StringBuilder sb = new StringBuilder();
161         sb.append(getValueOf(data));
162         sb.append(" ");
163         sb.append(operator.getRepr());
164         sb.append(" ");
165         sb.append(getThreshold());
166         return sb.toString();
167     }
168 
169     @Override
170     public List<Doublet<Parameter, Number>> getParameterDefaults() {
171         if (getParameters() == null) {
172             return List.of();
173         }
174         final Optional<Parameter> found = getParameters().stream() //
175                 .filter(a -> THRESHOLD.equals(a.getAttribute())) //
176                 .findFirst();
177         if (found.isEmpty()) {
178             return List.of();
179         }
180         return List.of(Doublet.of(found.get(), threshold));
181     }
182 
183     @Override
184     public Map<String, Double> getParametersValues() {
185         final Map<String, Double> val = new HashMap<>();
186         // if no substitution is defined
187         if (getParameters() == null) {
188             return val;
189         }
190         for (final Parameter param : getParameters()) {
191             if (Objects.equals(param.getAttribute(), THRESHOLD)) {
192                 val.put(param.getId(), threshold);
193             }
194         }
195         return val;
196     }
197 
198     /**
199      * @deprecated use operator
200      * @return always null for migration
201      */
202     @Deprecated(forRemoval = true)
203     public Boolean isInferiorToThreshold() {
204         return null;
205     }
206 
207     /**
208      * @deprecated use operator
209      * @return always null for migration.
210      */
211     @Deprecated(forRemoval = true)
212     public Boolean isStrict() {
213         return null;
214     }
215 
216     @Override
217     public void removeParameter(final Parameter param) {
218         if (this.getParameters() != null) {
219             this.getParameters().remove(param);
220         }
221     }
222 
223     /**
224      * @param value true for comparison inferior or inferior or equal, false for superior or superior or equal.
225      */
226     @XmlElement
227     public void setInferiorToThreshold(final Boolean value) {
228         this.inferiorToThreshold = value;
229         setOperator();
230     }
231 
232     /**
233      * Set operator according to inferiorToThreshold and strict.
234      */
235     private void setOperator() {
236         if (this.inferiorToThreshold) {
237             if (strict) {
238                 operator = RelationalOperator.LT;
239             } else {
240                 operator = RelationalOperator.LE;
241             }
242         } else {
243             if (strict) {
244                 operator = RelationalOperator.GT;
245             } else {
246                 operator = RelationalOperator.GE;
247             }
248         }
249     }
250 
251     @Override
252     public void setParametersValues(final Map<String, Double> values) {
253         // if no substitution is defined
254         if (getParameters() == null || values == null || values.isEmpty()) {
255             return;
256         }
257         for (final Parameter param : getParameters()) {
258             if (Objects.equals(param.getAttribute(), THRESHOLD)) {
259                 final String id = param.getId();
260                 if (values.containsKey(id) && values.get(id) != null) {
261                     if (values.get(id) == null) {
262                         LOGGER.error("Strange, value of parameter {} is null!", id);
263                     } else {
264                         setThreshold(values.get(id));
265                     }
266                 }
267             } else {
268                 LOGGER.error("Attribute {} not handled!", param.getAttribute());
269             }
270         }
271     }
272 
273     /**
274      * @param value Comparison is strictly inferior or superior.
275      */
276     @XmlElement
277     public void setStrict(final Boolean value) {
278         this.strict = value;
279         setOperator();
280     }
281 
282     /**
283      * @param value Threshold value.
284      */
285     public void setThreshold(final double value) {
286         final double old = threshold;
287         threshold = value;
288         getPropertySupport().firePropertyChange(THRESHOLD, old, value);
289     }
290 
291     @Override
292     public String toStringTree(final String ident) {
293         final StringBuilder sb = new StringBuilder();
294         sb.append(ident).append("  class: ").append(getClass().getName())
295         .append("\n");
296         sb.append(ident).append("  operator: ")
297         .append(operator.getRepr()).append("\n");
298         sb.append(ident).append("  noThreshold: ").append(noThreshold)
299         .append("\n");
300         sb.append(ident).append("  threshold: ").append(threshold)
301         .append("\n");
302         sb.append(ident).append("  variable: ").append(getVariable())
303         .append("\n");
304         return sb.toString();
305     }
306 }