MODULE moduleAverage
  USE moduleOutput

  TYPE:: averageData
    TYPE(outputNode), ALLOCATABLE:: output(:)
    TYPE(emNode):: emData

  END TYPE averageData

  !Generic type for average scheme
  TYPE, PUBLIC:: averageGeneric
    TYPE(averageData):: mean
    TYPE(averageData):: deviation
    CONTAINS
      PROCEDURE, PASS:: firstAverage
      PROCEDURE, PASS:: updateAverage

  END TYPE averageGeneric

  TYPE(averageGeneric), ALLOCATABLE:: averageScheme(:)

  !Logical to determine if average scheme must be used
  LOGICAL:: useAverage = .FALSE.
  INTEGER:: tAverageStart = 1 !Starting iteartion for average scheme

  CONTAINS
    PURE SUBROUTINE firstAverage(self, output)
      USE moduleOutput
      IMPLICIT NONE

      CLASS(averageGeneric), INTENT(inout):: self
      TYPE(outputNode), INTENT(in):: output(:)

      !Copy current data as mean
      self%mean%output(:) = output(:)

      !Set deviation at 0
      self%deviation%output(:) = 0.D0

    END SUBROUTINE firstAverage


    !Based on Welford's online algorithm
    SUBROUTINE updateAverage(self, output, tAverage)
      USE moduleOutput
      USE moduleSpecies, ONLY: nSpecies
      IMPLICIT NONE

      CLASS(averageGeneric), INTENT(inout):: self
      TYPE(outputNode), INTENT(in):: output(:)
      INTEGER, INTENT(in):: tAverage
      TYPE(averageData):: newMean, newDeviation

      ALLOCATE(newMean%output(1:nSpecies))
      ALLOCATE(newDeviation%output(1:nSpecies))

      newMean%output(:) =  self%mean%output(:) + (output(:) - self%mean%output(:))/tAverage

      newDeviation%output(:) = self%deviation%output(:) + ((output(:) - self%mean%output(:)) * &
                                                           (output(:) - newMean%output(:))   - &
                                                           self%deviation%output(:))/tAverage

      self%mean%output(:) = newMean%output(:)

      self%deviation%output(:) = newDeviation%output(:)

      DEALLOCATE(newMean%output)
      DEALLOCATE(newDeviation%output)
        
    END SUBROUTINE updateAverage

END MODULE moduleAverage
