NumberOfWaves.java

/*
 * 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 <https://www.gnu.org/licenses/>.
 */
package fr.inrae.agroclim.indicators.model.indicator;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.exception.type.ComputationErrorType;
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.util.Doublet;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

/**
 * Compute the number of period (nbDays) matching the criteria.
 *
 * @author jucufi
 */
@XmlAccessorType(XmlAccessType.FIELD)
@EqualsAndHashCode(
        callSuper = true,
        of = {"nbDays"}
        )
public final class NumberOfWaves extends SimpleIndicatorWithCriteria implements Detailable {
    /**
     * UUID for Serializable.
     */
    private static final long serialVersionUID = 6030595237342422011L;

    /**
     * Tag name.
     */
    static final String NB_OF_DAYS = "nbDays";

    /**
     * Number of step (day or hour) per wave.
     */
    @XmlElement(required = true)
    @Getter
    @Setter
    private Integer nbDays;

    /**
     * Constructor.
     */
    public NumberOfWaves() {
        super();
    }

    @Override
    public NumberOfWaves clone() throws CloneNotSupportedException {
        final NumberOfWaves clone = (NumberOfWaves) super.clone();
        clone.nbDays = nbDays;
        return clone;
    }

    @Override
    public double computeSingleValue(final Resource<? extends DailyData> climatic) throws IndicatorsException {
        if (getCriteria() == null) {
            throw new IndicatorsException(ComputationErrorType.CRITERIA_NULL);
        }
        if (nbDays == null) {
            throw new IndicatorsException(ComputationErrorType.WRONG_DEFINITION, "nbDays must not be null!");
        }
        int index = 0;
        int nb = 0;
        boolean resultCriteria;

        for (final DailyData data : climatic.getData()) {
            resultCriteria = getCriteria().eval(data);
            if (resultCriteria) {
                index += 1;
            } else {
                index = 0;
            }

            if (index >= nbDays) {
                nb += 1;
                index = 0;
            }

        }
        return nb;
    }

    @Override
    public List<Doublet<Parameter, Number>> getParameterDefaults() {
        if (getParameters() == null) {
            return List.of();
        }
        final List<Doublet<Parameter, Number>> val = new ArrayList<>();
        if (getCriteria() != null && getCriteria().getParameterDefaults() != null) {
            val.addAll(getCriteria().getParameterDefaults());
        }
        final Optional<Parameter> found = getParameters().stream() //
                .filter(a -> NB_OF_DAYS.equals(a.getAttribute())) //
                .findFirst();
        if (found.isPresent()) {
            val.add(Doublet.of(found.get(), nbDays));
        }
        return val;
    }

}