AggregationIndicator.java
package fr.inrae.agroclim.indicators.model.indicator;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.DoubleStream;
import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.exception.ThrowingToDoubleFunction;
import fr.inrae.agroclim.indicators.exception.type.ComputationErrorType;
import fr.inrae.agroclim.indicators.model.criteria.Criteria;
import fr.inrae.agroclim.indicators.model.criteria.NoCriteria;
import fr.inrae.agroclim.indicators.model.criteria.SimpleCriteria;
import fr.inrae.agroclim.indicators.model.criteria.VariableCriteria;
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 jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* Aggregate value defined in a {@link SimpleCriteria} using a {@link Function}
* on {@link DoubleStream} created for {@link AggregationIndicator#variable}.
*
* Last changed : $Date: 2023-06-16 10:36:46 +0200 (ven., 16 juin 2023) $
*
* @author omaury
*/
@EqualsAndHashCode(callSuper = true)
public abstract class AggregationIndicator extends SimpleIndicatorWithCriteria implements Detailable {
/**
* UUID for Serialize.
*/
private static final long serialVersionUID = 6030595237342422021L;
/**
* Variable to aggregate.
*/
@XmlElement(name = "variable")
@Getter
@Setter
private Variable variable;
/**
* @param stream stream to aggregate
* @return aggregated stream as single value.
*/
protected abstract double aggregate(DoubleStream stream);
/**
* Override {@link SimpleIndicatorWithCriteria#clone()}.
* @return clone
* @throws CloneNotSupportedException should not occur
*/
@Override
public AggregationIndicator clone() throws CloneNotSupportedException {
final AggregationIndicator clone = (AggregationIndicator) super.clone();
clone.variable = this.variable;
if (getCriteria() != null) {
clone.setCriteria(getCriteria().clone());
}
return clone;
}
@Override
public final double computeSingleValue(final Resource<? extends DailyData> res) throws IndicatorsException {
final DoubleStream stream;
try {
if (getCriteria() instanceof final NoCriteria criteria) {
Objects.requireNonNull(criteria.getVariable(),
getId() + ".getCriteria().getVariable() must not be null! " + getVariable());
// syntax changed to hack Eclipse.
stream = res.getData().stream() //
.mapToDouble(ThrowingToDoubleFunction.wrap(criteria::getValueOf));
} else if (getCriteria() instanceof final SimpleCriteria criteria) {
final Predicate<DailyData> predicate = d -> {
try {
return criteria.eval(d);
} catch (final IndicatorsException e) {
return false;
}
};
stream = res.getData().stream() //
.filter(predicate) //
.mapToDouble(ThrowingToDoubleFunction.wrap(criteria::getValueOf));
} else {
throw new IndicatorsException(ComputationErrorType.CRITERIA_ISNT_NOCRITERIA_SIMPLECRITERIA, getId());
}
return aggregate(stream);
} catch (final RuntimeException ex) {
if (ex.getCause() instanceof final IndicatorsException iex) {
throw iex;
}
throw ex;
}
}
@Override
public final Criteria getCriteria() {
if (super.getCriteria() == null) {
final var criteria = new NoCriteria();
criteria.setVariable(variable);
super.setCriteria(criteria);
}
if (super.getCriteria() instanceof VariableCriteria && this.variable != null) {
((VariableCriteria) super.getCriteria()).setVariable(this.variable);
}
return super.getCriteria();
}
/**
* To override, use super or use toStringTree(indent) and variable.
*
* @param indent intent of tree representation
* @return tree representation
*/
@Override
public String toStringTree(final String indent) {
final StringBuilder sb = new StringBuilder(super.toStringTree(indent));
sb.append(indent).append(" variable: ").append(variable).append("\n");
return sb.toString();
}
}