Calculate Nash-Sutcliffe coefficient(NSE) proposed by Nash and Sutcliffe (1970)
        and its variants.

           The following description is referred by Krause et al. (2005) and Moriasi et al. (2007).

             - The range of NSE lies between -inf and 1.0 (prefect fit).
             - Since the differences between observed and simulated values
               are calculated as squared values (expon=2), the larger values
               in a time series are strongly overestimated whereas lower
               values are neglected (Legates and McCabe, 1999). For the
               quantification of runoff prediction, this leads to an overestimation
               of the model performance during peak flows and an underestimation
               during low flow conditions.
             - Similar to R-square, NSE is not very sensitive to systematic
               model over- or underestimation especially during low flow periods.
             - To reduce the sensitivity of the original NSE to extreme values,
               the NSE is often calculated with logarithmic values of obseravtion
               and simulation values, which known as lnE. As a result, the
               influence of the low flow values is increased in comparison to the
               flood peaks resulting in an increase in sensitivity of lnE to
               systematic model over- or underestimation.
             - A more general form could be used for the same purpose as lnE, i.e.,
               varying the exponent from 1 to N. With the increase of `expon`, the
               sensitivity to high flows will increase and could be used when only
               the high flows are of interest, e.g., for flood prediction.

        Args:
            obsvalues: observation values array
            simvalues: simulation values array
            log: Do logarithmic transformation or not, False by default
            expon: The exponent range from 1 to N, 2 by default

        Examples:
            >>> obs = [2.92, 2.75, 2.01, 1.09, 2.87, 1.43, 1.96,\
                       4.00, 2.24, 29.28, 5.88, 0.86, 13.21]
            >>> sim = [2.90, 2.87, 2.85, 2.83, 3.04, 2.81, 2.85,\
                       2.78, 2.76, 13.40, 2.70, 2.09, 1.62]
            >>> MathClass.nashcoef(obs, sim)  # doctest: +ELLIPSIS
            0.451803966838596...
            >>> MathClass.nashcoef(obs, sim, log=True)  # doctest: +ELLIPSIS
            0.2841143016830745...
            >>> MathClass.nashcoef(obs, sim, expon=1)  # doctest: +ELLIPSIS
            0.3959646306103376...
            >>> MathClass.nashcoef(obs, sim, expon=3)  # doctest: +ELLIPSIS
            0.6122272075952075...
            >>> MathClass.nashcoef(obs, sim, expon=14)  # doctest: +ELLIPSIS
            0...
            >>> MathClass.nashcoef(obs, sim, expon=0)  # doctest: +ELLIPSIS
            0...

        Returns:
            NSE, or raise exception

def nashcoef(obsvalues,  # type: Union[numpy.ndarray, List[Union[float, int]]]
                 simvalues,  # type: Union[numpy.ndarray, List[Union[float, int]]]
                 log=False,  # type: bool
                 expon=2  # type: Union[float, int, numpy.ScalarType]
                 ):
        # type: (...) -> float
        """Calculate Nash-Sutcliffe coefficient(NSE) proposed by Nash and Sutcliffe (1970)
        and its variants.

           The following description is referred by Krause et al. (2005) and Moriasi et al. (2007).

             - The range of NSE lies between -inf and 1.0 (prefect fit).
             - Since the differences between observed and simulated values
               are calculated as squared values (expon=2), the larger values
               in a time series are strongly overestimated whereas lower
               values are neglected (Legates and McCabe, 1999). For the
               quantification of runoff prediction, this leads to an overestimation
               of the model performance during peak flows and an underestimation
               during low flow conditions.
             - Similar to R-square, NSE is not very sensitive to systematic
               model over- or underestimation especially during low flow periods.
             - To reduce the sensitivity of the original NSE to extreme values,
               the NSE is often calculated with logarithmic values of obseravtion
               and simulation values, which known as lnE. As a result, the
               influence of the low flow values is increased in comparison to the
               flood peaks resulting in an increase in sensitivity of lnE to
               systematic model over- or underestimation.
             - A more general form could be used for the same purpose as lnE, i.e.,
               varying the exponent from 1 to N. With the increase of `expon`, the
               sensitivity to high flows will increase and could be used when only
               the high flows are of interest, e.g., for flood prediction.

        Args:
            obsvalues: observation values array
            simvalues: simulation values array
            log: Do logarithmic transformation or not, False by default
            expon: The exponent range from 1 to N, 2 by default

        Examples:
            >>> obs = [2.92, 2.75, 2.01, 1.09, 2.87, 1.43, 1.96,\
                       4.00, 2.24, 29.28, 5.88, 0.86, 13.21]
            >>> sim = [2.90, 2.87, 2.85, 2.83, 3.04, 2.81, 2.85,\
                       2.78, 2.76, 13.40, 2.70, 2.09, 1.62]
            >>> MathClass.nashcoef(obs, sim)  # doctest: +ELLIPSIS
            0.451803966838596...
            >>> MathClass.nashcoef(obs, sim, log=True)  # doctest: +ELLIPSIS
            0.2841143016830745...
            >>> MathClass.nashcoef(obs, sim, expon=1)  # doctest: +ELLIPSIS
            0.3959646306103376...
            >>> MathClass.nashcoef(obs, sim, expon=3)  # doctest: +ELLIPSIS
            0.6122272075952075...
            >>> MathClass.nashcoef(obs, sim, expon=14)  # doctest: +ELLIPSIS
            0...
            >>> MathClass.nashcoef(obs, sim, expon=0)  # doctest: +ELLIPSIS
            0...

        Returns:
            NSE, or raise exception
        """
        if len(obsvalues) != len(simvalues):
            raise ValueError("The size of observed and simulated values must be"
                             " the same for NSE calculation!")
        if not isinstance(obsvalues, numpy.ndarray):
            obsvalues = numpy.array(obsvalues)
        if not isinstance(simvalues, numpy.ndarray):
            simvalues = numpy.array(simvalues)
        if log:  # Be care of zero values
            obsvalues = numpy.where((obsvalues == 0.) | (simvalues == 0.), numpy.nan, obsvalues)
            simvalues = numpy.where((obsvalues == 0.) | (simvalues == 0.), numpy.nan, simvalues)
            obsvalues = numpy.log(obsvalues)
            simvalues = numpy.log(simvalues)
        if expon > len(obsvalues) or expon < 1:
            return 0.
        ave = numpy.nanmean(obsvalues)
        a1 = numpy.nansum(numpy.abs(obsvalues - simvalues) ** expon)
        a2 = numpy.nansum(numpy.abs(obsvalues - ave) ** expon)
        if a2 == 0.:
            return 1.
        return 1. - a1 / a2