diff --git a/.gitlab/issue_templates/publier_nouvelle_version.md b/.gitlab/issue_templates/publier_nouvelle_version.md
index 908e8149455cb1cbeb37724266ee3af7722c7a5b..9ba22f2a3d394eda3bba02ee000f087f73b4c11a 100644
--- a/.gitlab/issue_templates/publier_nouvelle_version.md
+++ b/.gitlab/issue_templates/publier_nouvelle_version.md
@@ -3,9 +3,10 @@ Pour passer de la version *SNAPSHOT* à la version stable :
 - [ ] créer une demande de fusion et une branche à partir du ticket
 - [ ] changer la version dans `pom.xml`
   ```sh
-  mvn versions:set -DnewVersion=2.0.2
+  mvn versions:set -DnewVersion=2.1.0
   mvn versions:commit
   ```
+- [ ] mettre à jour `src/site/markdown/release-notes-fr.md`
 - [ ] mettre à jour les fichiers de métadonnées du projet
 - [ ] fusionner
 - [ ] déployer sur Archiva
diff --git a/pom.xml b/pom.xml
index 73b6018727b7f81a89c45274b64432d1eac90fdc..c354dd7323d2d09f41f06bd2351af582917e309d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@ along with Indicators. If not, see <https://www.gnu.org/licenses/>.
     <name>Indicators</name>
     <description>Library of agro- and eco-climatic indicators.</description>
     <inceptionYear>2018</inceptionYear>
-    <version>2.0.3-SNAPSHOT</version>
+    <version>2.1.0-SNAPSHOT</version>
     <packaging>jar</packaging>
     <licenses>
         <license>
@@ -382,11 +382,11 @@ along with Indicators. If not, see <https://www.gnu.org/licenses/>.
                 </executions>
             </plugin>
             <!-- Attach source and javadoc artifacts -->
-            <!-- https://maven.apache.org/plugin-developers/cookbook/attach-source-javadoc-artifacts.html -->
+            <!-- https://maven.apache.org/plugins/maven-source-plugin/usage.html -->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-source-plugin</artifactId>
-                <version>3.3.0</version>
+                <version>3.3.1</version>
                 <executions>
                     <execution>
                         <id>attach-sources</id>
diff --git a/src/main/java/fr/inrae/agroclim/indicators/model/Evaluation.java b/src/main/java/fr/inrae/agroclim/indicators/model/Evaluation.java
index 8e78e9e41151c11b9af6a12f31bce47aaa6ed37c..e228def7d35866fadcca0f32a7f7cb2d8d4eecf9 100644
--- a/src/main/java/fr/inrae/agroclim/indicators/model/Evaluation.java
+++ b/src/main/java/fr/inrae/agroclim/indicators/model/Evaluation.java
@@ -16,8 +16,6 @@
  */
 package fr.inrae.agroclim.indicators.model;
 
-import java.io.IOException;
-import java.io.ObjectInputStream;
 import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -34,6 +32,7 @@ import java.util.stream.Collectors;
 
 import fr.inrae.agroclim.indicators.exception.IndicatorsException;
 import fr.inrae.agroclim.indicators.exception.type.ResourceErrorType;
+import fr.inrae.agroclim.indicators.model.data.DailyData;
 import fr.inrae.agroclim.indicators.model.data.ResourceManager;
 import fr.inrae.agroclim.indicators.model.data.Variable;
 import fr.inrae.agroclim.indicators.model.data.Variable.Type;
@@ -106,21 +105,6 @@ public final class Evaluation extends CompositeIndicator {
         });
     }
 
-    /**
-     * Computed phases (or phases from file) used to compute indicators.
-     *
-     * TODO : supprimer et utiliser
-     * EvaluationResult::getPhaseResults::getAnnualPhase.
-     */
-    @Getter
-    private transient List<AnnualPhase> computedPhases;
-
-    /**
-     * Results of computation by year.
-     */
-    @Getter
-    private transient Map<Integer, EvaluationResult> results = new LinkedHashMap<>();
-
     /**
      * All resources needed to run the evaluation.
      *
@@ -129,6 +113,11 @@ public final class Evaluation extends CompositeIndicator {
     @Getter
     private final ResourceManager resourceManager;
 
+    /**
+     * Flag to ignore when climatic data is empty for a phase.
+     */
+    private boolean ignoreEmptyClimaticData = false;
+
     /**
      * Flag for state Saved.
      */
@@ -198,12 +187,7 @@ public final class Evaluation extends CompositeIndicator {
                 throw new RuntimeException("This should never occur!", ex);
             }
         }
-        if (evaluation.computedPhases != null) {
-            computedPhases = new ArrayList<>();
-            computedPhases.addAll(evaluation.computedPhases);
-        }
         isTranscient = evaluation.isTranscient;
-        results = evaluation.results;
         state = evaluation.state;
     }
 
@@ -285,11 +269,26 @@ public final class Evaluation extends CompositeIndicator {
     }
 
     /**
-     * Clear results of indicators.
+     * Check data before running compute* methods.
+     *
+     * @param phases phenological phases to check
+     * @param climaticResource climatic resource to check
+     * @throws IndicatorsException exception
      */
-    private void clearResults() {
-        results.clear();
-        computedPhases = new ArrayList<>();
+    private void checkBeforeCompute(final List<CompositeIndicator> phases, final ClimaticResource climaticResource)
+            throws IndicatorsException {
+        if (phases == null) {
+            throw new RuntimeException("Phase list is null!");
+        }
+        if (phases.isEmpty()) {
+            throw new RuntimeException("Phase list is empty!");
+        }
+        if (climaticResource.isEmpty()) {
+            throw new IndicatorsException(ResourceErrorType.CLIMATE_EMPTY);
+        }
+        if (resourceManager.getPhenologicalResource().isEmpty()) {
+            throw new IndicatorsException(ResourceErrorType.PHENO_EMPTY);
+        }
     }
 
     @Override
@@ -300,32 +299,30 @@ public final class Evaluation extends CompositeIndicator {
     /**
      * Compute indicator results.
      *
+     * @return Results of computation by year.
      * @throws IndicatorsException
      *             from Indicator.compute()
      */
-    public void compute() throws IndicatorsException {
+    public Map<Integer, EvaluationResult> compute() throws IndicatorsException {
         LOGGER.trace("start computing evaluation \"" + getName() + "\"");
+        this.ignoreEmptyClimaticData = false;
         fireIndicatorEvent(IndicatorEvent.Type.COMPUTE_START.event(this));
 
         final List<CompositeIndicator> phases = getPhases();
-        if (phases == null) {
-            throw new RuntimeException("Phase list is null!");
-        }
-        if (phases.isEmpty()) {
-            throw new RuntimeException("Phase list is empty!");
-        }
-        if (resourceManager.getClimaticResource().isEmpty()) {
-            throw new IndicatorsException(ResourceErrorType.CLIMATE_EMPTY);
-        }
-        if (resourceManager.getPhenologicalResource().isEmpty()) {
-            throw new IndicatorsException(ResourceErrorType.PHENO_EMPTY);
-        }
+        final ClimaticResource climaticResource = resourceManager.getClimaticResource();
+        checkBeforeCompute(phases, climaticResource);
 
-        clearResults();
+        var results = compute(climaticResource, phases);
+        fireIndicatorEvent(IndicatorEvent.Type.COMPUTE_SUCCESS.event(this));
+        return results;
+    }
+
+    private Map<Integer, EvaluationResult> compute(final ClimaticResource climaticResource,
+            final List<CompositeIndicator> phases) throws IndicatorsException {
+        final Map<Integer, EvaluationResult> results = new LinkedHashMap<>();
 
         /* Pour chaque phase */
-        List<AnnualStageData> stageDatas;
-        stageDatas = getResourceManager().getPhenologicalResource().getData();
+        final List<AnnualStageData> stageDatas = getResourceManager().getPhenologicalResource().getData();
         for (final CompositeIndicator phase : phases) {
             final String phaseId = phase.getId();
             if (phaseId == null) {
@@ -348,8 +345,7 @@ public final class Evaluation extends CompositeIndicator {
                     dateYear -= 1;
                 }
 
-                if (!resourceManager.getClimaticResource().getYears()
-                        .contains(dateYear)) {
+                if (!climaticResource.getYears().contains(dateYear)) {
                     continue;
                 }
 
@@ -368,7 +364,6 @@ public final class Evaluation extends CompositeIndicator {
                 annualPhase.setEndStage(endStageName);
                 annualPhase.setStartStage(startStageName);
                 annualPhase.setUid(phaseId);
-                computedPhases.add(annualPhase);
                 final PhaseResult phaseResult = new PhaseResult();
                 phaseResult.setAnnualPhase(annualPhase);
                 results.get(year).getPhaseResults().add(phaseResult);
@@ -399,15 +394,19 @@ public final class Evaluation extends CompositeIndicator {
                 }
 
                 /* Données climatiques pendant la phase et l'année donnée */
-                final ClimaticResource climaticData = resourceManager
-                        .getClimaticResource().getClimaticDataByPhaseAndYear(startDate, endDate);
+                final ClimaticResource climaticData = climaticResource
+                        .getClimaticDataByPhaseAndYear(startDate, endDate);
                 if (climaticData.isEmpty()) {
-                    if (resourceManager.getClimaticResource().isEmpty()) {
+                    if (climaticResource.isEmpty()) {
                         throw new IndicatorsException(ResourceErrorType.CLIMATE_EMPTY);
                     }
+                    if (ignoreEmptyClimaticData) {
+                        continue;
+                    }
                     final int yearToSearch = dateYear;
-                    final List<ClimaticDailyData> ddataList = resourceManager.getClimaticResource().getData()
-                            .stream().filter(f -> f.getYear() == yearToSearch).collect(Collectors.toList());
+                    final List<ClimaticDailyData> ddataList = climaticResource.getData().stream() //
+                            .filter(f -> f.getYear() == yearToSearch) //
+                            .collect(Collectors.toList());
 
                     final ClimaticDailyData startData = ddataList.get(0);
                     final ClimaticDailyData endData = ddataList.get(ddataList.size() - 1);
@@ -433,9 +432,40 @@ public final class Evaluation extends CompositeIndicator {
             }
         }
 
-        computeFaisability();
-        fireIndicatorEvent(IndicatorEvent.Type.COMPUTE_SUCCESS.event(this));
+        computeFaisability(results);
         LOGGER.trace("end of computing evaluation \"{}\"", getName());
+        return results;
+    }
+
+    /**
+     * Compute indicator results for each step of provided climatic data.
+     *
+     * @return Results of computation by year, for each step in climatic data:
+     * Climatic date ⮕ (year, {@link EvalutationResult}).
+     * @throws IndicatorsException
+     *             from Indicator.compute()
+     */
+    public Map<LocalDate, Map<Integer, EvaluationResult>> computeEachDate() throws IndicatorsException {
+        this.ignoreEmptyClimaticData = true;
+        final List<CompositeIndicator> phases = getPhases();
+        final ClimaticResource climaticResource = resourceManager.getClimaticResource();
+        checkBeforeCompute(phases, climaticResource);
+
+        final List<ClimaticDailyData> dailyData = climaticResource.getData();
+        // first, create Maps
+        final Map<LocalDate, Map<Integer, EvaluationResult>> allResults = new LinkedHashMap<>();
+        dailyData.stream().map(DailyData::getLocalDate).forEach(date -> allResults.put(date, new LinkedHashMap<>()));
+        // then compute
+        final ClimaticResource resource = new ClimaticResource();
+        resource.setMissingVariables(climaticResource.getMissingVariables());
+        for (int i = 0; i < dailyData.size(); i++) {
+            final List<ClimaticDailyData> data = dailyData.subList(0, i);
+            resource.setData(data);
+            final Map<Integer, EvaluationResult> results = compute(resource, phases);
+            final LocalDate date = dailyData.get(i).getLocalDate();
+            allResults.put(date, results);
+        }
+        return allResults;
     }
 
     /**
@@ -448,9 +478,10 @@ public final class Evaluation extends CompositeIndicator {
      * Pour chaque année, Pour chaque phase, valeurs.onIndicatorAdd(valeur phase
      * p, année n); Fin pour aggregation(valeurs); Fin pour;
      *
+     * @param results Results of computation by year.
      * @throws IndicatorsException raised by AggregationFunction.aggregate()
      */
-    private void computeFaisability() throws IndicatorsException {
+    private void computeFaisability(final Map<Integer, EvaluationResult> results) throws IndicatorsException {
         LOGGER.traceEntry();
         if (getType() == EvaluationType.WITHOUT_AGGREGATION) {
             return;
@@ -459,18 +490,14 @@ public final class Evaluation extends CompositeIndicator {
             // if only 1 phase, no need to aggregate
             // evaluation value = value of the phase
             results.values().forEach(result ->
-            result.setNormalizedValue(
-                    result.getPhaseResults().get(0).getNormalizedValue()
-                    )
-                    );
+                    result.setNormalizedValue(result.getPhaseResults().get(0).getNormalizedValue()));
             return;
         } else if (getAggregationFunction().getExpression() == null) {
             throw new IllegalStateException("An evaluation with more than 1 "
                     + "phase must have a defined expression for aggregation!");
         }
 
-        for (final Map.Entry<Integer, EvaluationResult> entry
-                : results.entrySet()) {
+        for (final Map.Entry<Integer, EvaluationResult> entry : results.entrySet()) {
             final EvaluationResult evaluationResult = entry.getValue();
             final int year = entry.getKey();
             if (evaluationResult == null) {
@@ -872,22 +899,6 @@ public final class Evaluation extends CompositeIndicator {
         return result;
     }
 
-    /**
-     * Context: Deserialization does not initialize results.
-     *
-     * A final field must be initialized either by direct assignment of an initial value or in the constructor. During
-     * deserialization, neither of these are invoked, so initial values for transients must be set in the
-     * 'readObject()' private method that's invoked during deserialization. And for that to work, the transients must
-     * be non-final.
-     *
-     * @param ois input stream from deserialization
-     */
-    private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
-        // perform the default de-serialization first
-        ois.defaultReadObject();
-        results = new HashMap<>();
-    }
-
     /**
      * Set parameters (id and attributes) for the indicator and its criteria
      * from knowledge defined in settings.
diff --git a/src/main/java/fr/inrae/agroclim/indicators/model/data/HourlyData.java b/src/main/java/fr/inrae/agroclim/indicators/model/data/HourlyData.java
index 5c6f5c2803a6bd8228fcdc9587325b508585d0ed..97ecc1477185353e784f38ad440b72ab98885c2d 100644
--- a/src/main/java/fr/inrae/agroclim/indicators/model/data/HourlyData.java
+++ b/src/main/java/fr/inrae/agroclim/indicators/model/data/HourlyData.java
@@ -21,6 +21,7 @@ import java.util.Calendar;
 import java.util.Date;
 
 import fr.inrae.agroclim.indicators.util.DateUtils;
+import java.time.LocalDate;
 import lombok.Getter;
 
 /**
@@ -174,6 +175,15 @@ public abstract class HourlyData implements Cloneable, Data, Serializable {
         return DateUtils.getDoy(getDate());
     }
 
+    /**
+     * Create date object with {@code day}, {@code month}, {@code year} and {@code hour} attribute.<br>
+     * If at least one of these attributes is null, then the returned date is null.
+     * @return date object
+     */
+    public LocalDate getLocalDate() {
+        return DateUtils.asLocalDate(getDate());
+    }
+
     /**
      * Get value for variable as it was set.
      *
diff --git a/src/main/java/fr/inrae/agroclim/indicators/model/indicator/CompositeIndicator.java b/src/main/java/fr/inrae/agroclim/indicators/model/indicator/CompositeIndicator.java
index c0af4e5e5dbc4cfa4ad98f6a35129ec47a2437c0..b639fc7017df7c3cdbbdd415c9a71268afb205bf 100644
--- a/src/main/java/fr/inrae/agroclim/indicators/model/indicator/CompositeIndicator.java
+++ b/src/main/java/fr/inrae/agroclim/indicators/model/indicator/CompositeIndicator.java
@@ -252,14 +252,14 @@ implements DataLoadingListener, Detailable, HasDataLoadingListener, Comparable<I
     }
 
     @Override
-    public final Double compute(final Resource<? extends DailyData> climRessource) throws IndicatorsException {
-        if (climRessource.getYears().isEmpty()) {
+    public final Double compute(final Resource<? extends DailyData> climResource) throws IndicatorsException {
+        if (climResource.getYears().isEmpty()) {
             throw new RuntimeException(
                     String.format(
                             "No years in ClimaticResource (%d dailyData)!",
-                            climRessource.getData().size()));
+                            climResource.getData().size()));
         }
-        final HashMap<String, Double> results = new HashMap<>();
+        final Map<String, Double> results = new HashMap<>();
         double valueAfterAggregation = 0;
         Double valueAfterNormalization;
 
@@ -274,7 +274,7 @@ implements DataLoadingListener, Detailable, HasDataLoadingListener, Comparable<I
             }
 
             try {
-                final double value = indicator.compute(climRessource);
+                final Double value = indicator.compute(climResource);
                 results.put(indicator.getId(), value);
             } catch (final IndicatorsException e) {
                 throw new IndicatorsException(ComputationErrorType.COMPOSITE_COMPUTATION, e, indicator.getId());
@@ -651,18 +651,6 @@ implements DataLoadingListener, Detailable, HasDataLoadingListener, Comparable<I
         getIndicators().forEach(i -> i.setParametersValues(values));
     }
 
-    /**
-     * Detect if aggregation function is needed but missing.
-     *
-     * @param fire fire events while checking
-     * @return true if aggregation function is needed but missing
-     * @deprecated use {@link CompositeIndicator#isAggregationMissing(boolean)}.
-     */
-    @Deprecated(since = "2.0.1", forRemoval = true)
-    public final boolean toAggregate(final boolean fire) {
-        return isAggregationMissing(fire);
-    }
-
     @Override
     public final String toStringTree(final String indent) {
         final StringBuilder sb = new StringBuilder();
diff --git a/src/main/java/fr/inrae/agroclim/indicators/model/indicator/Indicator.java b/src/main/java/fr/inrae/agroclim/indicators/model/indicator/Indicator.java
index 22969b6ce942f706238ea43f43320a201c808da7..e383f79e9c58b43b21c9c899b37b8cd7e29e835a 100644
--- a/src/main/java/fr/inrae/agroclim/indicators/model/indicator/Indicator.java
+++ b/src/main/java/fr/inrae/agroclim/indicators/model/indicator/Indicator.java
@@ -186,6 +186,7 @@ Serializable, UseVariables {
      * Normalized value.
      */
     @XmlTransient
+    @Getter
     @Setter
     private Double value;
 
@@ -225,8 +226,8 @@ Serializable, UseVariables {
             }
         }
         listeners.add(IndicatorListener.class, listener);
-        if (this instanceof CompositeIndicator) {
-            ((CompositeIndicator) this).getIndicators()
+        if (this instanceof CompositeIndicator compositeIndicator) {
+            compositeIndicator.getIndicators()
             .forEach(i -> i.addIndicatorListener(listener));
         }
     }
@@ -364,15 +365,6 @@ Serializable, UseVariables {
      */
     public abstract EvaluationType getType();
 
-    /**
-     * The normalized value.
-     *
-     * @return Normalized value
-     */
-    public final Double getValue() {
-        return value;
-    }
-
     /**
      * @param indicatorCategory indicator category
      */
diff --git a/src/main/java/fr/inrae/agroclim/indicators/model/result/EvaluationResult.java b/src/main/java/fr/inrae/agroclim/indicators/model/result/EvaluationResult.java
index 70782bf192970c64842148aac4ddf90283a4f9ce..d0fba97c8568481b5087dd470998c7a7d8449b02 100644
--- a/src/main/java/fr/inrae/agroclim/indicators/model/result/EvaluationResult.java
+++ b/src/main/java/fr/inrae/agroclim/indicators/model/result/EvaluationResult.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import lombok.Getter;
+import lombok.ToString;
 
 /**
  * Normalized value of an evaluation for a year and values of composed phases.
@@ -30,6 +31,7 @@ import lombok.Getter;
  * @author $Author$
  * @version $Revision$
  */
+@ToString
 public class EvaluationResult extends Result {
 
     /**
diff --git a/src/site/markdown/release-notes-fr.md b/src/site/markdown/release-notes-fr.md
new file mode 100644
index 0000000000000000000000000000000000000000..d9c7ccf1cd03dcce76a02deb4596a4562c38db09
--- /dev/null
+++ b/src/site/markdown/release-notes-fr.md
@@ -0,0 +1,32 @@
+---
+title: Notes de version
+description: Modifications de la bibliothèque d'indicateurs.
+keywords: "version"
+date: 2024-08-19
+---
+
+# [v2.1.0](https://forgemia.inra.fr/agroclim/Indicators/indicators-java/-/releases/v2.1.0) −
+
+- Ajouter la méthode `Evaluation.computeEachDate()`.
+- Renvoyer les résultats de calcul par la méthode `Evaluation.compute()` et ne plus les stocker dans `Evaluation`.
+- Supprimer `Evaluation#getResults()`.
+- Supprimer `Evaluation#getComputedPhases()`.
+- Supprimer de `CompositeIndicator#toAggregate(boolean)`.
+
+# [v2.0.2](https://forgemia.inra.fr/agroclim/Indicators/indicators-java/-/releases/v2.0.2) − 11 juillet 2024
+
+- Passer à Jakarta XML Binding.
+
+# [v2.0.1](https://forgemia.inra.fr/agroclim/Indicators/indicators-java/-/releases/v2.0.1) − 5 avril 2024
+
+- Ajouter le modèle phénologique Richardson.
+- Renommer `CompositeIndicator.toAggregate(boolean)`.
+- Corriger l'id et la référence d'indicateurs THI.
+- Dépréciation `CompositeIndicator#toAggregate(boolean)`.
+
+# [v2.0.0](https://forgemia.inra.fr/agroclim/Indicators/indicators-java/-/releases/v2.0.0) − 18 janvier 2024
+
+- Gestion des données climatiques manquantes.
+- Changement de gestion des exceptions et affichage de codes d'erreurs.
+- Passage sous GitLab.
+- Mise en ligne de la documentation.
diff --git a/src/site/site.xml b/src/site/site.xml
index 0f490a9957e4395f831950839cbe92b575cd2423..89ea402eb4e21c771e16fafa29ee2fbd3f684924 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -30,6 +30,7 @@
             <item name="Indicateurs journaliers" href="indicators-daily-fr.html" />
             <item name="Codes d'erreurs" href="errors-fr.html" />
             <item name="Modèles phénologiques" href="pheno-fr.html" />
+            <item name="Notes de version" href="release-notes-fr.html" />
             <item name="Documentation in English" href="en/index.html" />
         </menu>
         <menu ref="modules" inherit="top" />
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationEachDateTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationEachDateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..95dfba5c3926f3406d45bedd21e916b01560fc13
--- /dev/null
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationEachDateTest.java
@@ -0,0 +1,178 @@
+package fr.inrae.agroclim.indicators.model;
+
+import fr.inrae.agroclim.indicators.exception.IndicatorsException;
+import fr.inrae.agroclim.indicators.model.data.DataTestHelper;
+import fr.inrae.agroclim.indicators.model.indicator.CompositeIndicator;
+import fr.inrae.agroclim.indicators.model.indicator.Indicator;
+import fr.inrae.agroclim.indicators.model.result.EvaluationResult;
+import fr.inrae.agroclim.indicators.model.result.IndicatorResult;
+import fr.inrae.agroclim.indicators.model.result.PhaseResult;
+import fr.inrae.agroclim.indicators.util.DateUtils;
+import java.io.File;
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test {@link Evaluation#computeEachDate()}.
+ *
+ * @author Olivier Maury
+ */
+public class EvaluationEachDateTest extends DataTestHelper {
+
+    /**
+     * The only year in climatic data.
+     */
+    private static final Integer YEAR = 2015;
+
+    /**
+     * Evaluation from good XML file.
+     */
+    private static Evaluation evaluation;
+
+    /**
+     * Computation results.
+     */
+    private static Map<LocalDate, Map<Integer, EvaluationResult>> results;
+
+    /**
+     * DOY of Stage 0.
+     */
+    private static final int S0 = 120;
+
+    /**
+     * DOY of Stage 0 plus 1 day.
+     */
+    private static final int S0_PLUS_1 = S0 + 1;
+
+    /**
+     * DOY of Stage 1.
+     */
+    private static final int S1 = 140;
+
+    /**
+     * Set up Evaluation to test.
+     *
+     * Check if evaluation computes.
+     */
+    @BeforeClass
+    public static void beforeTest() {
+        final File xmlFile = getFile("xml/evaluation-phalen.gri");
+        evaluation = getEvaluation(xmlFile);
+        assertTrue("Evaluation must not be null!", evaluation != null);
+        try {
+            evaluation.initializeResources();
+            results = evaluation.computeEachDate();
+        } catch (final IndicatorsException e) {
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+        }
+    }
+
+    /**
+     * Ensure only 2015 has data.
+     */
+    @Test
+    public void years() {
+        assertNotNull(results);
+
+        assertEquals(evaluation.getClimaticResource().getData().size(), results.size());
+        final List<Integer> years = results.values().stream().flatMap(m -> m.keySet().stream()).distinct().toList();
+        assertNotNull(years);
+        assertEquals(1, years.size());
+        assertEquals(YEAR, years.get(0));
+    }
+
+    /**
+     * Ensure only 1 indicator is computed.
+     */
+    @Test
+    public void indicators() {
+        // s0s1 : phalen
+        final List<Indicator> indicators = new ArrayList<>();
+        final List<Indicator> allIndicators = new ArrayList<>();
+        allIndicators.addAll(evaluation.getIndicators());
+        Indicator indicator = allIndicators.remove(0);
+        while (indicator != null) {
+            if (indicator instanceof CompositeIndicator c) {
+                allIndicators.addAll(c.getIndicators());
+            } else {
+                indicators.add(indicator);
+            }
+            if (!allIndicators.isEmpty()) {
+                indicator = allIndicators.remove(0);
+            } else {
+                indicator = null;
+            }
+        }
+        final int nbOfIndicators = indicators.size();
+        assertEquals(1, nbOfIndicators);
+    }
+
+    /**
+     * Ensure no data is returned out of s0s1.
+     */
+    @Test
+    public void noDataOutOfPhase() {
+        // no data on 1st january 2015 as no phase
+        final Optional<LocalDate> firstDateOptional = results.keySet().stream().findFirst();
+        assertTrue(firstDateOptional.isPresent());
+        final LocalDate firstDate = firstDateOptional.get();
+        final LocalDate expectedFirstDate = LocalDate.of(YEAR, Month.JANUARY, 1);
+        assertEquals(expectedFirstDate, firstDate);
+        assertFalse(results.get(firstDate).containsKey(YEAR));
+    }
+
+    /**
+     * Ensure data are return each date of s0s1.
+     */
+    @Test
+    public void dataInPhase() {
+        for (int doy = S0_PLUS_1; doy < S1; doy++) {
+            final LocalDate date = DateUtils.asLocalDate(DateUtils.getDate(YEAR, doy));
+            final List<PhaseResult> phaseResults = results.get(date).get(YEAR).getPhaseResults();
+            assertFalse(phaseResults.isEmpty());
+            assertEquals(1, phaseResults.size());
+            final List<IndicatorResult> processResults = phaseResults.get(0).getIndicatorResults();
+            assertNotNull("On " + date + "/" + doy + ", process results must not be null!", processResults);
+            assertEquals(1, processResults.size());
+            assertEquals("growth", processResults.get(0).getIndicatorId());
+
+            // practices > growth > phalength > phalen
+            final List<IndicatorResult> practicesResults = processResults.get(0).getIndicatorResults();
+            assertEquals("phalength", practicesResults.get(0).getIndicatorId());
+            List<IndicatorResult> indicatorResults = practicesResults.get(0).getIndicatorResults();
+            assertEquals("phalen", indicatorResults.get(0).getIndicatorId());
+            Double value = indicatorResults.get(0).getRawValue();
+            assertNotNull("On " + date + "/" + doy + ", phalen must not be null!", value);
+        }
+    }
+
+    /**
+     * Check computed values for each date.
+     */
+    @Test
+    public void checkData() {
+        for (int doy = S0_PLUS_1; doy < S1; doy++) {
+            final LocalDate date = DateUtils.asLocalDate(DateUtils.getDate(YEAR, doy));
+            final List<PhaseResult> phaseResults = results.get(date).get(YEAR).getPhaseResults();
+            final List<IndicatorResult> processResults = phaseResults.get(0).getIndicatorResults();
+            final List<IndicatorResult> practicesResults = processResults.get(0).getIndicatorResults();
+            final List<IndicatorResult> indicatorResults = practicesResults.get(0).getIndicatorResults();
+            final Double value = indicatorResults.get(0).getRawValue();
+            assertNotNull("On " + date + "/" + doy + ", phalen must not be null!", value);
+            final Double expected = Double.valueOf(doy - S0);
+            assertEquals("On " + date + "/" + doy + ", phalen must equal " + expected, expected, value);
+        }
+    }
+}
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationHourlyTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationHourlyTest.java
index f90f64f02a78d61b89621df94754f98da23efe15..0de0bdb9c049098fddb1ae4afb2103d9b69972a1 100644
--- a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationHourlyTest.java
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationHourlyTest.java
@@ -2,8 +2,8 @@ package fr.inrae.agroclim.indicators.model;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.util.List;
@@ -52,16 +52,16 @@ public class EvaluationHourlyTest extends DataTestHelper {
     @Test
     public void compute() {
         assertTrue("Evaluation must not be null!", evaluation != null);
-        String error = null;
+        final Map<Integer, EvaluationResult> results;
         try {
             evaluation.initializeResources();
-            evaluation.compute();
+            results = evaluation.compute();
         } catch (final IndicatorsException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
 
-        final Map<Integer, EvaluationResult> results = evaluation.getResults();
         assertNotNull(results);
         assertEquals(1, results.keySet().size());
         assertTrue(results.containsKey(2015));
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationRobertTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationRobertTest.java
index 8e99a6bcc81a37985ea5f3912e28807b5bf8f31c..38d6032269a66be0b9c3aaac50641feaf54f894f 100644
--- a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationRobertTest.java
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationRobertTest.java
@@ -20,8 +20,8 @@ package fr.inrae.agroclim.indicators.model;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.util.Arrays;
@@ -80,16 +80,16 @@ public class EvaluationRobertTest extends DataTestHelper {
     @Test
     public void compute() {
         assertTrue("Evaluation must not be null!", evaluation != null);
-        String error = null;
+        final Map<Integer, EvaluationResult> results;
         try {
             evaluation.initializeResources();
-            evaluation.compute();
+            results = evaluation.compute();
         } catch (final IndicatorsException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
 
-        final Map<Integer, EvaluationResult> results = evaluation.getResults();
         assertNotNull(results);
         assertEquals(2, results.keySet().size());
         assertTrue(results.containsKey(1991));
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationTest.java
index a3f975d440362218c78939090d20dd93caa464e9..0603a053344e58168965dcd3287b09f62e9bd5f3 100644
--- a/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationTest.java
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/EvaluationTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -184,8 +185,11 @@ public final class EvaluationTest extends DataTestHelper {
         String error = null;
         try {
             evaluation.initializeResources();
-            evaluation.compute();
-            final List<AnnualPhase> phases = evaluation.getComputedPhases();
+            final Map<Integer, EvaluationResult> results = evaluation.compute();
+            final List<AnnualPhase> phases = results.values().stream() //
+                    .flatMap(r -> r.getPhaseResults().stream()) //
+                    .map(r -> r.getAnnualPhase()) //
+                    .toList();
             final int nbOfPhases = evaluation.getIndicators().size();
             final int nbOfYears = evaluation.getClimaticResource().getYears().size();
             assertEquals(nbOfPhases * nbOfYears, phases.size());
@@ -238,8 +242,7 @@ public final class EvaluationTest extends DataTestHelper {
         final String fmt = "%s | %4d | %s-%s | %f | %f";
         try {
             evaluation.initializeResources();
-            evaluation.compute();
-            final Map<Integer, EvaluationResult> results = evaluation.getResults();
+            final Map<Integer, EvaluationResult> results = evaluation.compute();
             assertNotNull("Results must not be null!", results);
             results.entrySet().forEach((entryER) -> {
                 final Integer year = entryER.getKey();
@@ -420,15 +423,16 @@ public final class EvaluationTest extends DataTestHelper {
     public void setParameters() {
         assertTrue("Evaluation must not be null!", evaluation != null);
         String error = null;
+        Map<Integer, EvaluationResult> results;
         try {
             evaluation.initializeResources();
-            evaluation.compute();
+            results = evaluation.compute();
         } catch (final IndicatorsException e) {
             error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
 
-        final Map<Integer, EvaluationResult> results = evaluation.getResults();
         final Double initValue = getResultValue("s0s1", "heat", 2015, results);
         assertNotNull("value of climatic effect \"heat\" must not be null", initValue);
 
@@ -438,11 +442,11 @@ public final class EvaluationTest extends DataTestHelper {
         parameters.put("Theat", 25.);
         evaluation.setParametersValues(parameters);
         try {
-            evaluation.compute();
+            results = evaluation.compute();
         } catch (IndicatorsException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
 
         final Double newValue = getResultValue("s0s1", "heat", 2015, results);
         assertNotEquals("init = " + initValue + ", new = " + newValue, initValue, newValue);
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/EvalutationCustomHeadersTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/EvalutationCustomHeadersTest.java
index d226c65e8f14753ba7ba49ca7baa7d4aa46b4f81..d02a249d7e78c0e67eee34eb894431e37387fea8 100644
--- a/src/test/java/fr/inrae/agroclim/indicators/model/EvalutationCustomHeadersTest.java
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/EvalutationCustomHeadersTest.java
@@ -20,8 +20,8 @@ package fr.inrae.agroclim.indicators.model;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.util.Map;
@@ -63,15 +63,15 @@ public class EvalutationCustomHeadersTest extends DataTestHelper {
     @Test
     public void compute() {
         assertTrue("Evaluation must not be null!", evaluation != null);
-        String error = null;
+        final Map<Integer, EvaluationResult> results;
         try {
             evaluation.initializeResources();
-            evaluation.compute();
+            results = evaluation.compute();
         } catch (final IndicatorsException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
-        final Map<Integer, EvaluationResult> results = evaluation.getResults();
         assertNotNull("Results must not be null!", results);
         assertEquals("One year en climate file", 1, results.keySet().size());
         results.values().stream().flatMap(v -> v.getPhaseResults().stream()).forEach(phaseResult -> {
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/MMarjouTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/MMarjouTest.java
index 826138824f84f7314d2a0e33ed80c815b6e18e27..a102b23ac2427707322be6657ca861ae5270836c 100644
--- a/src/test/java/fr/inrae/agroclim/indicators/model/MMarjouTest.java
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/MMarjouTest.java
@@ -17,7 +17,6 @@
 package fr.inrae.agroclim.indicators.model;
 
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -35,6 +34,7 @@ import fr.inrae.agroclim.indicators.model.result.EvaluationResult;
 import fr.inrae.agroclim.indicators.model.result.IndicatorResult;
 import fr.inrae.agroclim.indicators.model.result.PhaseResult;
 import lombok.extern.log4j.Log4j2;
+import static org.junit.Assert.fail;
 
 /**
  * Test that Marine Marjou's Getari file computes.
@@ -76,16 +76,17 @@ public class MMarjouTest extends DataTestHelper {
     @Test
     public void raidaysInfNbDaysInPhase() {
         assertTrue("Evaluation must not be null!", evaluation != null);
-        String error = null;
+        final Map<Integer, EvaluationResult> results;
         try {
             evaluation.initializeResources();
             long start = System.currentTimeMillis();
-            evaluation.compute();
+            results = evaluation.compute();
             LOGGER.info("Evaluation.compute() last {} seconds", (System.currentTimeMillis() - start) / 1000.);
         } catch (final IndicatorsException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
         // extract stages to compute number of days
         Map<Integer, Map<String, Integer>> stageDates = new HashMap<>();
         List<AnnualStageData> aSDatas;
@@ -100,9 +101,8 @@ public class MMarjouTest extends DataTestHelper {
             });
         });
         // check excraidays, hraidays and raidays
-        assertFalse(evaluation.getResults().isEmpty());
+        assertFalse(results.isEmpty());
         String fmt = "%d | %s %s : %d | %s=%.4f";
-        Map<Integer, EvaluationResult> results = evaluation.getResults();
         for (Map.Entry<Integer, EvaluationResult> entry : results.entrySet()) {
             Integer year = entry.getKey();
             if (!stageDates.containsKey(year)) {
diff --git a/src/test/java/fr/inrae/agroclim/indicators/model/RaidayMeantTest.java b/src/test/java/fr/inrae/agroclim/indicators/model/RaidayMeantTest.java
index c9c8ba33ee6693c1c93fb225b2730447543df802..c31942d796a984e3d3eaf7bc831108afcb43255d 100644
--- a/src/test/java/fr/inrae/agroclim/indicators/model/RaidayMeantTest.java
+++ b/src/test/java/fr/inrae/agroclim/indicators/model/RaidayMeantTest.java
@@ -19,8 +19,8 @@ package fr.inrae.agroclim.indicators.model;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.IOException;
@@ -208,8 +208,8 @@ public class RaidayMeantTest extends DataTestHelper {
     @Test
     public void computeUsingPhenologyCalculator() {
         assertTrue("Evaluation must not be null!", evaluation != null);
-        String error = null;
-        List<AnnualStageData> annualStageDatas = null;
+        final List<AnnualStageData> annualStageDatas;
+        final Map<Integer, EvaluationResult> results;
         try {
             final EvaluationSettings settings = evaluation.getSettings();
             // wheat Soissons
@@ -221,25 +221,29 @@ public class RaidayMeantTest extends DataTestHelper {
             settings.getPhenologyLoader().setCalculator(calc);
             settings.getPhenologyLoader().setFile(null);
             evaluation.initializeResources();
-            evaluation.compute();
+            results = evaluation.compute();
             annualStageDatas = evaluation.getResourceManager().getPhenologicalResource().getData();
         } catch (final IndicatorsException | IOException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
 
         // first year in phenology file
         final int firstYear = 1959;
         assertNotNull(annualStageDatas);
         assertFalse(annualStageDatas.isEmpty());
         assertTrue(firstYear == annualStageDatas.get(0).getYear());
-        final List<AnnualPhase> computedPhases = evaluation.getComputedPhases();
+        final List<AnnualPhase> computedPhases = results.values().stream() //
+                .flatMap(r -> r.getPhaseResults().stream()) //
+                .map(r -> r.getAnnualPhase()) //
+                .toList();
         assertNotNull(computedPhases);
         assertFalse(computedPhases.isEmpty());
         assertTrue(firstYear == computedPhases.get(0).getHarvestYear());
         compareStagesAndPhases(annualStageDatas, computedPhases);
 
-        assertFalse(evaluation.getResults().isEmpty());
+        assertFalse(results.isEmpty());
     }
 
     /**
@@ -248,14 +252,15 @@ public class RaidayMeantTest extends DataTestHelper {
     @Test
     public void compute() {
         assertTrue("Evaluation must not be null!", evaluation != null);
-        String error = null;
+        final Map<Integer, EvaluationResult> results;
         try {
             evaluation.initializeResources();
-            evaluation.compute();
+            results = evaluation.compute();
         } catch (final IndicatorsException e) {
-            error = e.getClass() + " : " + e.getLocalizedMessage();
+            final String error = e.getClass() + " : " + e.getLocalizedMessage();
+            fail(error);
+            return;
         }
-        assertNull(error, error);
         // extract stages to compute number of days
         final Map<Integer, Map<String, Integer>> stageDates = new HashMap<>();
         List<AnnualStageData> aSDatas;
@@ -271,9 +276,9 @@ public class RaidayMeantTest extends DataTestHelper {
         });
 
         // check excraidays, hraidays and raidays
-        assertFalse(evaluation.getResults().isEmpty());
+        assertFalse(results.isEmpty());
         final String fmt = "%d | %s %s : %d | %s=%.4f";
-        for (final Map.Entry<Integer, EvaluationResult> entry : evaluation.getResults().entrySet()) {
+        for (final Map.Entry<Integer, EvaluationResult> entry : results.entrySet()) {
             final Integer year = entry.getKey();
             if (!stageDates.containsKey(year)) {
                 LOGGER.trace("No stage date for year {}", year);
@@ -317,14 +322,16 @@ public class RaidayMeantTest extends DataTestHelper {
         }
 
         assertNotNull(aSDatas);
-        final List<AnnualPhase> computedPhases = evaluation.getComputedPhases();
+        final List<AnnualPhase> computedPhases = results.values().stream() //
+                .flatMap(r -> r.getPhaseResults().stream()) //
+                .map(r -> r.getAnnualPhase()) //
+                .toList();
         compareStagesAndPhases(aSDatas, computedPhases);
 
-        Map<String, Map<Integer, Map<String, Double>>> computation;
-        computation = new HashMap<>();
+        final Map<String, Map<Integer, Map<String, Double>>> computation = new HashMap<>();
 
-        evaluation.getResults().forEach((year, results) -> {
-            results.getPhaseResults().forEach((phase) -> {
+        results.forEach((year, r) -> {
+            r.getPhaseResults().forEach((phase) -> {
                 final String phaseId = phase.getPhaseId();
                 if (!computation.containsKey(phaseId)) {
                     computation.put(phaseId, new HashMap<>());
diff --git a/src/test/resources/fr/inrae/agroclim/indicators/xml/evaluation-phalen.gri b/src/test/resources/fr/inrae/agroclim/indicators/xml/evaluation-phalen.gri
new file mode 100644
index 0000000000000000000000000000000000000000..b11858c38bd5999cb95fee74f30d9e58d242736b
--- /dev/null
+++ b/src/test/resources/fr/inrae/agroclim/indicators/xml/evaluation-phalen.gri
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!DOCTYPE evaluationSettings PUBLIC
+    "-//INRAE AgroClim.//DTD Evaluation 1.1//EN"
+    "https://agroclim.inrae.fr/getari/dtd/1.1/evaluation.dtd">
+<evaluationSettings timescale="DAILY" timestamp="2024-08-19T14:26:01.505524546" version="2.0.1+20240405062628">
+    <climate>
+        <file path="../model/data/climate/climate-2015.csv">
+            <separator>	</separator>
+            <header></header>
+            <header>year</header>
+            <header>month</header>
+            <header>day</header>
+            <header>tmin</header>
+            <header>tmax</header>
+            <header>tmean</header>
+            <header></header>
+            <header>radiation</header>
+            <header>rain</header>
+            <header>rh</header>
+            <header>wind</header>
+            <header>ETP</header>
+            <midnight>0</midnight>
+        </file>
+    </climate>
+    <notes/>
+    <phenology>
+        <file path="../model/data/phenology/pheno_sample.csv">
+            <separator>;</separator>
+            <header>year</header>
+            <header>s0</header>
+            <header>s1</header>
+            <header>s2</header>
+            <header>s3</header>
+            <header>s4</header>
+        </file>
+    </phenology>
+    <name>evaluation-phalen</name>
+    <type>WITH_AGGREGATION</type>
+    <compositeIndicator>
+        <name>root-test</name>
+        <name xml:lang="en">evaluation-test</name>
+        <id>root-evaluation</id>
+        <timescale>DAILY</timescale>
+        <tag>practices</tag>
+        <aggregationFunction xsi:type="jexlFunction" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
+        <indicator xsi:type="compositeIndicator" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+            <name>s1</name>
+            <id>s0s1</id>
+            <category>pheno</category>
+            <color>#5F9EA0</color>
+            <timescale>DAILY</timescale>
+            <tag>pheno-s0-s1</tag>
+            <indicator xsi:type="compositeIndicator">
+                <name>s0</name>
+                <id>pheno_s0</id>
+                <category>pheno</category>
+                <color>#5F9EA0</color>
+                <timescale>DAILY</timescale>
+                <normalizationFunction xsi:type="exponential" expA="0.0" expB="0.0"/>
+                <tag>pheno-s0-s1</tag>
+            </indicator>
+            <indicator xsi:type="compositeIndicator">
+                <name xml:lang="en">Crop growth</name>
+                <name xml:lang="fr">Développement cultural</name>
+                <id>growth</id>
+                <category>ecoprocesses</category>
+                <color>#5F9EA0</color>
+                <timescale>DAILY</timescale>
+                <indicator xsi:type="compositeIndicator">
+                    <name xml:lang="fr">Durée de la phase</name>
+                    <name xml:lang="en">Phase length</name>
+                    <id>phalength</id>
+                    <category>climatic</category>
+                    <color>#5F9EA0</color>
+                    <timescale>DAILY</timescale>
+                    <indicator xsi:type="phaseLength">
+                        <description xml:lang="fr">Durée de la phase.</description>
+                        <description xml:lang="en">Phase length.</description>
+                        <name xml:lang="fr">Durée de la phase</name>
+                        <name xml:lang="en">Phase length</name>
+                        <id>phalen</id>
+                        <category>indicator</category>
+                        <color>#5F9EA0</color>
+                        <timescale>DAILY</timescale>
+                        <normalizationFunction xsi:type="sigmoid" sigmoidA="30.0" sigmoidB="4.0"/>
+                        <unit>day</unit>
+                    </indicator>
+                </indicator>
+            </indicator>
+        </indicator>
+    </compositeIndicator>
+</evaluationSettings>