NS2LOG.java [src/csip/cosu] Revision:   Date:
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API and application suite.
 *
 * 2012-2022, Olaf David and others, OMSLab, Colorado State University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package csip.cosu;

/**
 * Calculates the efficiency between the log values of a test data set and a
 * verification data set after Nash & Sutcliffe (1970). The efficiency is
 * described as the proportion of the cumulated cubic deviation between both
 * data sets and the cumulated cubic deviation between the verification data
 * set and its mean value.
 */
class NS2LOG extends ObjFunc {

  @Override
  public String name() {
    return "Nash Sutcliffe";
  }


  @Override
  public double eval(double[] obs, double[] sim, double missing) {
    checkArrays(sim, obs);
    int size = sim.length;
    double sum_log_vd = 0;
    /**
     * calculating logarithmic values of both data sets. Sets 0 if data is 0
     */
    double[] log_preData = new double[size];
    double[] log_valData = new double[size];
    int validPairs = 0;
    for (int i = 0; i < size; i++) {
      //either prediction or validation shows a value of zero
      //in this case the pair is excluded from the further calculation,
      //simply by setting the values to -1 and not increasing valid pairs
      // this will also catch missing values
      if (sim[i] <= 0 || obs[i] <= 0) {
        log_preData[i] = -1;
        log_valData[i] = -1;
      }
      //both prediction and validation shows a value of exact zero
      //in this case the pair is taken as a perfect fit and included
      //into the further calculation
      if (sim[i] == 0 && obs[i] == 0) {
        log_preData[i] = 0;
        log_valData[i] = 0;
        validPairs++;
      }
      //both prediction and validation are greater than zero
      //no problem for the calculation
      if (sim[i] > 0 && obs[i] > 0) {
        log_preData[i] = Math.log(sim[i]);
        log_valData[i] = Math.log(obs[i]);
        validPairs++;
      }
    }
    /*
     * summing up both data sets
     */
    for (int i = 0; i < size; i++) {
      if (log_preData[i] >= 0) {
        //          sum_log_pd += log_preData[i];
        sum_log_vd += log_valData[i];
      }
    }
    /*
     * calculating mean values for both data sets
     */
    double mean_log_vd = sum_log_vd / validPairs;
    /*
     * calculating mean pow deviations
     */
    double pd_log_vd = 0;
    double vd_log_mean = 0;
    for (int i = 0; i < size; i++) {
      if (log_preData[i] >= 0) {
        pd_log_vd += (Math.pow(Math.abs(log_valData[i] - log_preData[i]), 2.0));
        vd_log_mean += (Math.pow(Math.abs(log_valData[i] - mean_log_vd), 2.0));
      }
    }
    return 1 - (pd_log_vd / vd_log_mean);
  }


  @Override
  public int direction() {
    return 1;
  }


  @Override
  public int optimum() {
    return 1;
  }
  
}