Tamm.java
/*
* Copyright (C) 2020 INRAE AgroClim
*
* This file is part of Indicators.
*
* Indicators is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Indicators is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Indicators. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.inrae.agroclim.indicators.model.indicator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.model.Knowledge;
import fr.inrae.agroclim.indicators.model.Parameter;
import fr.inrae.agroclim.indicators.model.data.DailyData;
import fr.inrae.agroclim.indicators.model.data.Resource;
import fr.inrae.agroclim.indicators.model.data.Variable;
import fr.inrae.agroclim.indicators.model.data.climate.ClimaticResource;
import fr.inrae.agroclim.indicators.util.Doublet;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
/**
* Risk of Monilia during a period.
*
* Fonction de calcul du %age de fleurs de cerisier moniliees (Monilia laxa)
* établie par Tamm et al. (1995) à l'aide de mesures en chambres climatiques
* (in vitro).
*
* https://dx.doi.org/10.1016/j.eja.2019.125960
*
* Last changed : $Date$
*
* @author $Author$
* @version $Revision$
*/
@XmlType(propOrder = {"e", "gamma1", "gamma2", "imax", "m", "ro1", "ro2",
"tMax", "tMin", "threshold"})
public final class Tamm extends SimpleIndicator implements Detailable {
/**
* UUID for Serializable.
*/
private static final long serialVersionUID = 6030595237342422019L;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 31.
*/
@Getter
@Setter
private Double tMax = 31.;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 0.
*/
@Getter
@Setter
private Double tMin = 0.;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 0.9.
*/
@Getter
@Setter
private Double m = 0.9;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 0.874.
*/
@Getter
@Setter
private Double imax = 0.79;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 1.816.
*/
@Getter
@Setter
private Double gamma1 = 1.709;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 1.736.
*/
@Getter
@Setter
private Double gamma2 = 1.47221;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 0.728.
*/
@Getter
@Setter
private Double ro1 = 1.5751;
/**
* Valeur par défaut issue de Tamm et al., 1995 : 0.918.
*/
@Getter
@Setter
private Double ro2 = 1.9652;
/**
* Facteur pluvio/(pluvio+E) pour forcer le modèle à 0 pour pluvio = 0.
*/
@Getter
@Setter
private double e = 0.029;
/**
* Seuil infectieux.
*/
@Getter
@Setter
private double threshold = 0.50;
/**
* @param data daily data
* @return weighted risk for a day.
*/
public double computeDailyValue(final DailyData data) {
final double rain = data.getValue(Variable.RAIN);
final double tmean = data.getValue(Variable.TMEAN);
final double phi = (tmean - tMin) / (tMax - tMin);
final double intermI0 = Math.pow(phi, gamma2);
final double i0 = gamma1 * intermI0 * (1 - phi);
final double intermR = Math.pow(phi, ro2);
final double r = ro1 * intermR * (1 - phi);
final double term1 = 1 - Math.pow(i0, 1 - m);
final double term2 = Math.exp(-r * rain);
final double partA = rain / (rain + e);
final double partB = Math.pow(1 - term1 * term2, 1 / (1 - m));
final double flowerRisk = partA * imax * partB;
if (flowerRisk < threshold) {
return 0;
}
return flowerRisk;
}
@Override
public double computeSingleValue(final Resource<? extends DailyData> data) throws IndicatorsException {
return data.getData().stream() //
.map(this::computeDailyValue) //
.reduce((v1, v2) -> v1 + v2).orElseThrow();
}
@Override
public List<Doublet<Parameter, Number>> getParameterDefaults() {
// no substitution
return List.of();
}
/**
* @return no parameters for the indicator.
*/
@Override
public List<Parameter> getParameters() {
return List.of();
}
@Override
public Map<String, Double> getParametersValues() {
// no substitution
return Map.of();
}
@Override
public Set<Variable> getVariables() {
final Set<Variable> variables = new HashSet<>();
variables.add(Variable.RAIN);
variables.add(Variable.TMEAN);
return variables;
}
@Override
public boolean isComputable(final Resource<? extends DailyData> res) {
if (res == null) {
throw new IllegalArgumentException("resource must no be null!");
}
if (!(res instanceof ClimaticResource)) {
throw new IllegalArgumentException(getClass().getName()
+ " handles only ClimaticResource, not "
+ res.getClass().getName());
}
return true;
}
@Override
public void setParametersFromKnowledge(final Knowledge knowledge) {
// no substitution
}
@Override
public void setParametersValues(final Map<String, Double> values) {
// no substitution
}
@Override
public String toStringTree(final String indent) {
return toStringTreeBase(indent);
}
@Override
public void removeParameter(final Parameter param) {
// no substitution: nothing to do
}
}