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.data.soil;
18  
19  import java.io.File;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.Date;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import fr.inrae.agroclim.indicators.model.TimeScale;
29  import fr.inrae.agroclim.indicators.model.data.DataLoadingListenerHandler;
30  import fr.inrae.agroclim.indicators.model.data.Resource;
31  import fr.inrae.agroclim.indicators.model.data.Variable;
32  import fr.inrae.agroclim.indicators.model.data.climate.ClimaticDailyData;
33  import jakarta.xml.bind.annotation.XmlAccessType;
34  import jakarta.xml.bind.annotation.XmlAccessorType;
35  import jakarta.xml.bind.annotation.XmlElement;
36  import jakarta.xml.bind.annotation.XmlTransient;
37  import lombok.Getter;
38  import lombok.Setter;
39  import lombok.extern.log4j.Log4j2;
40  
41  /**
42   * Proxy to load soil data.
43   *
44   * Loader is chosen according to properties (XML tag).
45   *
46   * The proxy is initialized from evaluation XML file.
47   *
48   * Last changed : $Date$
49   *
50   * @author $Author$
51   * @version $Revision$
52   */
53  @Log4j2
54  @XmlAccessorType(XmlAccessType.FIELD)
55  public final class SoilLoaderProxy extends DataLoadingListenerHandler implements HasSoilCalculatorParams, SoilLoader {
56      /**
57       * UID for serialization.
58       */
59      private static final long serialVersionUID = 4796900688021151186L;
60  
61      /**
62       * Climatic daily data used to compute soil water balance.
63       */
64      @XmlTransient
65      private List<ClimaticDailyData> climaticDailyData;
66  
67      /**
68       * CSV file.
69       */
70      @XmlElement(name = "file")
71      @Getter
72      @Setter
73      private File file;
74  
75      /**
76       * Headers of CSV file.
77       */
78      @XmlElement(name = "header")
79      @Getter
80      @Setter
81      private String[] headers;
82  
83      /**
84       * Coefficient cultural en situation non stressée durant la période initiale
85       * de la saison [0-1] (semis-levee selon notre hypothèse).
86       */
87      private Double kcIni;
88  
89      /**
90       * Coefficient cultural en situation non stressée durant la late season
91       * [0-1] (à partir de floraison selon nous).
92       */
93      private Double kcLate;
94  
95      /**
96       * Coefficient cultural en situation non stressée durant la middle season
97       * [0-1] (epi 1 cm - floraison selon notre hypothèse).
98       */
99      private Double kcMid;
100 
101     /**
102      * Loader/Calculator for soil data.
103      */
104     @XmlTransient
105     private SoilLoader loader;
106 
107     /**
108      * Proportion of easily available water in the soil.
109      *
110      * Average fraction of TAW(pour obtenir RAW).
111      */
112     private Double p;
113 
114     /**
115      * Réserve utile du sol (mm).
116      *
117      * Ou utilisation de swcFc, swcWp, soilDepth.
118      */
119     private Double ru;
120 
121     /**
122      * CSV separator.
123      */
124     @XmlElement(name = "separator")
125     @Getter
126     @Setter
127     private String separator = Resource.DEFAULT_SEP;
128 
129     /**
130      * Soil depth (cm).
131      */
132     private Double soilDepth;
133 
134     /**
135      * 4 stages per year to compute soil water balance (SWC and R).
136      */
137     @XmlTransient
138     @Getter
139     private List<Date> stages;
140 
141     /**
142      * Teneur en eau du sol à la capacité au champ (% volumique).
143      */
144     private Double swcFc;
145 
146     /**
147      * Teneur en eau du sol ... (% volumique).
148      */
149     private double swcMax;
150 
151     /**
152      * Teneur en eau du sol au point de flétrissement permanent (% volumique).
153      */
154     private Double swcWp;
155 
156     /**
157      * Constructor.
158      */
159     public SoilLoaderProxy() {
160         super();
161     }
162 
163     @Override
164     public SoilLoaderProxy clone() throws CloneNotSupportedException {
165         final SoilLoaderProxy clone = (SoilLoaderProxy) super.clone();
166         if (climaticDailyData != null) {
167             clone.climaticDailyData = new ArrayList<>();
168             Collections.copy(clone.climaticDailyData, climaticDailyData);
169         }
170         clone.file = file;
171         clone.headers = headers;
172         clone.kcIni = kcIni;
173         clone.kcLate = kcLate;
174         clone.kcMid = kcMid;
175         clone.loader = loader.clone();
176         clone.p = p;
177         clone.ru = ru;
178         clone.separator = separator;
179         clone.soilDepth = soilDepth;
180         if (stages != null) {
181             clone.stages = new ArrayList<>();
182             Collections.copy(clone.stages, stages);
183         }
184         clone.swcFc = swcFc;
185         clone.swcMax = swcMax;
186         clone.swcWp = swcWp;
187         return clone;
188     }
189 
190     @Override
191     public Map<String, String> getConfigurationErrors() {
192         return getLoader().getConfigurationErrors();
193     }
194 
195     /**
196      * @return loader/calculator for soil data according to configuration.
197      */
198     public SoilLoader getLoader() {
199         if (loader == null) {
200             if (file != null) {
201                 final SoilFileLoader soilFileLoader = new SoilFileLoader(getFile(),
202                         getHeaders(), getSeparator());
203                 soilFileLoader
204                 .addDataLoadingListeners(getDataLoadingListeners());
205                 loader = soilFileLoader;
206             } else {
207                 final SoilCalculator calc = new SoilCalculator();
208                 calc.setClimaticDailyData(climaticDailyData);
209                 calc.setStages(stages);
210                 calc.setKcIni(kcIni);
211                 calc.setKcLate(kcLate);
212                 calc.setKcMid(kcMid);
213                 calc.setP(p);
214                 calc.setRu(ru);
215                 calc.setSoilDepth(soilDepth);
216                 calc.setSwcFc(swcFc);
217                 calc.setSwcMax(swcMax);
218                 calc.setSwcWp(swcWp);
219                 calc.addDataLoadingListeners(getDataLoadingListeners());
220                 loader = calc;
221             }
222         }
223         return loader;
224     }
225 
226     @Override
227     public Collection<String> getMissingVariables() {
228         throw new RuntimeException("Not implemented for soil!");
229     }
230 
231     @Override
232     public Set<Variable> getProvidedVariables() {
233         return getLoader().getProvidedVariables();
234     }
235 
236     @Override
237     public Set<Variable> getVariables() {
238         return getLoader().getVariables();
239     }
240 
241     @Override
242     public List<SoilDailyData> load() {
243         return getLoader().load();
244     }
245 
246     /**
247      * @param calc model for soil water balance
248      */
249     public void setCalculator(final SoilCalculator calc) {
250         loader = calc;
251     }
252 
253     /**
254      * @param values Climatic daily data used to compute soil water balance.
255      */
256     public void setClimaticDailyData(final List<ClimaticDailyData> values) {
257         this.climaticDailyData = values;
258         if (loader instanceof final SoilCalculator calc) {
259             calc.setClimaticDailyData(values);
260         } else {
261             LOGGER.warn("No soil loader!");
262         }
263     }
264 
265     @Override
266     public void setKcIni(final Double value) {
267         this.kcIni = value;
268     }
269 
270     @Override
271     public void setKcLate(final Double value) {
272         this.kcLate = value;
273     }
274 
275     @Override
276     public void setKcMid(final Double value) {
277         this.kcMid = value;
278     }
279 
280     @Override
281     public void setP(final Double value) {
282         p = value;
283     }
284 
285     @Override
286     public void setSoilDepth(final Double value) {
287         this.soilDepth = value;
288     }
289 
290     /**
291      * @param values 4 stages per year to compute soil water balance (SWC and
292      * R).
293      */
294     public void setStages(final List<Date> values) {
295         this.stages = values;
296         if (loader instanceof final SoilCalculator calc) {
297             calc.setStages(stages);
298         }
299     }
300 
301     @Override
302     public void setSwcFc(final Double value) {
303         this.swcFc = value;
304     }
305 
306     @Override
307     public void setSwcMax(final Double value) {
308         this.swcMax = value;
309     }
310 
311     @Override
312     public void setSwcWp(final Double value) {
313         this.swcWp = value;
314     }
315 
316     @Override
317     public void setTimeScale(final TimeScale timeScale) {
318         // do nothing
319     }
320 }