docs: 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