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.indicator;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import fr.inrae.agroclim.indicators.exception.IndicatorsException;
27  import fr.inrae.agroclim.indicators.exception.type.ComputationErrorType;
28  import fr.inrae.agroclim.indicators.model.Knowledge;
29  import fr.inrae.agroclim.indicators.model.Parameter;
30  import fr.inrae.agroclim.indicators.model.data.DailyData;
31  import fr.inrae.agroclim.indicators.model.data.Resource;
32  import fr.inrae.agroclim.indicators.model.data.Variable;
33  import fr.inrae.agroclim.indicators.model.indicator.listener.IndicatorEvent;
34  import fr.inrae.agroclim.indicators.model.indicator.listener.IndicatorListener;
35  import fr.inrae.agroclim.indicators.util.Doublet;
36  import jakarta.xml.bind.annotation.XmlAccessType;
37  import jakarta.xml.bind.annotation.XmlAccessorType;
38  import jakarta.xml.bind.annotation.XmlRootElement;
39  import jakarta.xml.bind.annotation.XmlType;
40  import lombok.Getter;
41  import lombok.Setter;
42  
43  /**
44   * Computing quotient of indicators (dividend/divisor).
45   *
46   * Last changed : $Date$
47   *
48   * @author $Author$
49   * @version $Revision$
50   */
51  @XmlRootElement
52  @XmlAccessorType(XmlAccessType.FIELD)
53  @XmlType(propOrder = {"dividend", "divisor"})
54  public final class Quotient extends SimpleIndicator implements Detailable, IndicatorListener {
55  
56      /**
57       * UUID for Serializable.
58       */
59      private static final long serialVersionUID = 6030595237342422014L;
60  
61      /**
62       * Dividend in quotient or numerator in fraction.
63       */
64      @Getter
65      @Setter
66      private SimpleIndicator dividend;
67  
68      /**
69       * Divisor or denominator in fraction.
70       */
71      @Getter
72      @Setter
73      private SimpleIndicator divisor;
74  
75      /**
76       * Constructor.
77       */
78      public Quotient() {
79          super();
80      }
81  
82      @Override
83      public Quotient clone() throws CloneNotSupportedException {
84          final Quotient clone = (Quotient) super.clone();
85          if (dividend != null) {
86              clone.dividend = (SimpleIndicator) dividend.clone();
87          }
88          if (divisor != null) {
89              clone.divisor = (SimpleIndicator) divisor.clone();
90          }
91          return clone;
92      }
93  
94      @Override
95      public double computeSingleValue(final Resource<? extends DailyData> data) throws IndicatorsException {
96          if (dividend == null) {
97              throw new IndicatorsException(ComputationErrorType.QUOTIENT_DIVIDEND_NULL);
98          }
99          if (divisor == null) {
100             throw new IndicatorsException(ComputationErrorType.QUOTIENT_DIVISOR_NULL);
101         }
102         final double dividendValue;
103         try {
104             dividendValue = dividend.compute(data);
105         } catch (final IndicatorsException e) {
106             throw new IndicatorsException(ComputationErrorType.QUOTIENT_DIVIDEND_EXCEPTION, e, dividend.getId());
107         }
108         final double divisorValue;
109         try {
110             divisorValue = divisor.compute(data);
111         } catch (final IndicatorsException e) {
112             throw new IndicatorsException(ComputationErrorType.QUOTIENT_DIVISOR_EXCEPTION, e, divisor.getId());
113         }
114         if (divisorValue == 0.0) {
115             throw new IndicatorsException(ComputationErrorType.QUOTIENT_DIVISOR_ZERO, divisor.getId());
116         }
117         return dividendValue / divisorValue;
118     }
119 
120     @Override
121     public List<Doublet<Parameter, Number>> getParameterDefaults() {
122         final List<Doublet<Parameter, Number>> val = new ArrayList<>();
123         if (dividend != null && dividend.getParameterDefaults() != null) {
124             val.addAll(dividend.getParameterDefaults());
125         }
126         if (divisor != null && divisor.getParameterDefaults() != null) {
127             val.addAll(divisor.getParameterDefaults());
128         }
129         return val;
130     }
131 
132     @Override
133     public List<Parameter> getParameters() {
134         final List<Parameter> params = new ArrayList<>();
135         if (dividend != null && dividend.getParameters() != null) {
136             params.addAll(dividend.getParameters());
137         }
138         if (divisor != null && divisor.getParameters() != null) {
139             params.addAll(divisor.getParameters());
140         }
141         return params;
142     }
143 
144     @Override
145     public Map<String, Double> getParametersValues() {
146         final Map<String, Double> val = new HashMap<>();
147         if (dividend != null && dividend.getParametersValues() != null) {
148             val.putAll(dividend.getParametersValues());
149         }
150         if (divisor != null && divisor.getParametersValues() != null) {
151             val.putAll(divisor.getParametersValues());
152         }
153         return val;
154     }
155 
156     @Override
157     public Set<Variable> getVariables() {
158         final Set<Variable> variables = new HashSet<>();
159         if (dividend != null) {
160             variables.addAll(dividend.getVariables());
161         }
162         if (divisor != null) {
163             variables.addAll(divisor.getVariables());
164         }
165         return variables;
166     }
167 
168     @Override
169     public boolean isComputable(final Resource<? extends DailyData> data) {
170         if (dividend == null || divisor == null) {
171             return false;
172         }
173         return dividend.isComputable(data) && divisor.isComputable(data);
174     }
175 
176     @Override
177     public void onIndicatorEvent(final IndicatorEvent event) {
178         if (event.getAssociatedType() != IndicatorEvent.Type.CHANGE) {
179             return;
180         }
181         final IndicatorEvent e = IndicatorEvent.Type.CHANGE.event(this);
182         fireIndicatorEvent(e);
183     }
184 
185     @Override
186     public void setParametersFromKnowledge(final Knowledge knowledge) {
187         if (dividend != null) {
188             dividend.setParametersFromKnowledge(knowledge);
189         }
190         if (divisor != null) {
191             divisor.setParametersFromKnowledge(knowledge);
192         }
193     }
194 
195     @Override
196     public void setParametersValues(final Map<String, Double> values) {
197         if (dividend != null) {
198             dividend.setParametersValues(values);
199         }
200         if (divisor != null) {
201             divisor.setParametersValues(values);
202         }
203     }
204 
205     @Override
206     public String toStringTree(final String indent) {
207         final StringBuilder sb = new StringBuilder();
208         sb.append(toStringTreeBase(indent));
209 
210         if (dividend != null) {
211             sb.append(indent).append("  dividend:\n");
212             sb.append(dividend.toStringTree(indent + "  "))
213             .append("\n");
214         }
215         if (divisor != null) {
216             sb.append(indent).append("  divisor:\n");
217             sb.append(divisor.toStringTree(indent + "  "))
218             .append("\n");
219         }
220 
221         return sb.toString();
222     }
223 
224     @Override
225     public void removeParameter(final Parameter param) {
226         if (dividend != null) {
227             this.dividend.removeParameter(param);
228         }
229         if (divisor != null) {
230             this.divisor.removeParameter(param);
231         }
232     }
233 }