Skip to content
Snippets Groups Projects
ch_cranck.f90 6.14 KiB
Newer Older
  • Learn to ignore specific revisions
  • !MNH_LIC Copyright 1994-2014 CNRS, Meteo-France and Universite Paul Sabatier
    
    !MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
    
    !MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
    
    !MNH_LIC for details. version 1.
    
    !-----------------------------------------------------------------
    !--------------- special set of characters for RCS information
    !-----------------------------------------------------------------
    ! $Source$ $Revision$
    ! MASDEV4_7 chimie 2006/05/18 13:07:25
    !-----------------------------------------------------------------
    !!    ##################### 
          MODULE MODI_CH_CRANCK
    !!    ##################### 
    !!
    !
    INTERFACE
    !!
    SUBROUTINE CH_CRANCK(PTSIMUL, PDTACT, PCONC, PNEWCONC, KEQ, KVECNPT, KMI, &
                           PALPHA)
    IMPLICIT NONE
    REAL,    INTENT(IN) :: PTSIMUL  ! time of simulation
    REAL,    INTENT(IN) :: PDTACT   ! actual time-step
    INTEGER, INTENT(IN) :: KEQ      ! dimension of the problem to solve
    INTEGER, INTENT(IN) :: KVECNPT
    REAL, INTENT(IN),  DIMENSION(KVECNPT,KEQ) :: PCONC    ! concentration vector at PTSIMUL
    REAL, INTENT(OUT), DIMENSION(KVECNPT,KEQ) :: PNEWCONC ! solution at PTSIMUL + PDTACT
    INTEGER, INTENT(IN) :: KMI      ! model number
    REAL, INTENT(IN) :: PALPHA
    END SUBROUTINE CH_CRANCK
    !!
    END INTERFACE
    !!
    END MODULE MODI_CH_CRANCK
    !!    ######################################################################### 
    SUBROUTINE CH_CRANCK(PTSIMUL, PDTACT, PCONC, PNEWCONC, KEQ, KVECNPT, KMI, &
                           PALPHA)
    !!    #########################################################################
    !!
    !!*** *CH_CRANCK*
    !!
    !!    PURPOSE
    !!    -------
    !     solve one time-step of the chemical differential equation d/dt y = f(y)
    !!
    !!**  METHOD
    !!    ------
    !!    Cranck-Nicholson method (CRANCK):
    !!    y^n+1 = y^n + dt*( alpha*f^n + (1-alpha)f^n-1 )
    !!    for alpha = 1   the method reduces to EULER EXPLICIT
    !!    for alpha = 0   the method reduces to EULER IMPLICIT
    !!    for alpha = 1/2 the method reduces to EULER SEMI-IMPLICIT
    !!    The implicit equation is solved by Newton-Raphson iteration:
    !!    z^m+1 = z^m - (DF)(z^m)^-1 * F(z^m)
    !!    where F(z) = z - y^n - dt*( alpha*f^n + (1-alpha)f(z) )
    !!    the iteration process should yield:  z^m --> y^n+1 for increasing m
    !!
    !!    REFERENCE
    !!    ---------
    !!    J. Stoer: Einf\"uhrung in die Numerische Mathematik I & II,
    !!    Heidelberger Taschenb\"ucher, Springer Verlag, Berlin, 1983 & 1978.
    !!
    !!    AUTHOR
    !!    ------
    !!    K. Suhre   *Laboratoire d'Aerologie*
    !!
    !!    MODIFICATIONS
    !!    -------------
    !!    Original 12/06/95
    !!    31/07/96 (K. Suhre) restructured
    !!    19/04/02 add PALPHA argument
    !!    01/12/03  (Gazen)   change Chemical scheme interface
    !!    EXTERNAL
    !!    --------
    USE MODI_CH_FCN
    USE MODI_CH_JAC
    USE MODI_CH_GAUSS
    !!
    !!    IMPLICIT ARGUMENTS
    !!    ------------------
    !!
    !------------------------------------------------------------------------------
    !
    !*       0.   DECLARATIONS
    !        -----------------
    IMPLICIT NONE
    !
    !*       0.1  declaration of arguments
    !
    REAL,    INTENT(IN) :: PTSIMUL  ! time of simulation
    REAL,    INTENT(IN) :: PDTACT   ! actual time-step
    INTEGER, INTENT(IN) :: KEQ      ! dimension of the problem to solve
    INTEGER, INTENT(IN) :: KVECNPT
    REAL, INTENT(IN),  DIMENSION(KVECNPT,KEQ) :: PCONC    ! concentration vector at PTSIMUL
    REAL, INTENT(OUT), DIMENSION(KVECNPT,KEQ) :: PNEWCONC ! solution at PTSIMUL + PDTACT
    INTEGER, INTENT(IN) :: KMI      ! model number
    REAL, INTENT(IN) :: PALPHA
    !
    !*       0.2  declaration of local variables
    !
    INTEGER :: IFAIL, JI, JJ
    INTEGER :: IITERCOUNT      ! counter for Newton-Raphson iteration
    INTEGER :: IMAXITER = 20   ! maximal # of iterations before faillure
    REAL, DIMENSION(KVECNPT) :: ZERR            ! error in iteration
    REAL    :: ZMAXERR = 1E-6  ! maximal relative error for solution of implicit eqn
    REAL    :: ZNORM           ! vector norm for calculation of relative error
    REAL, DIMENSION(KVECNPT,KEQ) :: ZYN      ! stores y^n + dt**alpha*f^n
    REAL, DIMENSION(KVECNPT,KEQ) :: ZF       ! f(y)
    REAL, DIMENSION(KEQ) :: ZFTRAPEZ ! F(z^m), then z^m+1 - z^m
    REAL, DIMENSION(KVECNPT,KEQ) :: ZFTRAPEZVECT ! F(z^m), then z^m+1 - z^m
    REAL, DIMENSION(KEQ,KEQ) :: ZB,ZC   ! working matrice for the iteration
    REAL, DIMENSION(KVECNPT,KEQ,KEQ) :: ZBVECT 
    
    !------------------------------------------------------------------------------
    !
    !*       1.   CALCULATE FIRST GUESS FOR ITERATION (ZYN)
    !        ----------------------------------------------
    !
    CALL CH_FCN(PTSIMUL,PCONC,ZF,KMI,KVECNPT,KEQ)
    ZYN(:,:) = PCONC(:,:) + PALPHA*PDTACT*ZF(:,:)
    PNEWCONC(:,:) = PCONC(:,:)
    !
    !*       2.   NEWTON RAPHSON ITERATION
    !        -----------------------------
    !
    ZERR(:) = 2.*ZMAXERR
    IITERCOUNT = 0
    newton: DO WHILE (MAXVAL(ZERR).GT.ZMAXERR)
    !
      IITERCOUNT = IITERCOUNT + 1
      IF (IITERCOUNT.GT.IMAXITER) THEN
    !callabortstop
        CALL ABORT
        STOP "CH_CRANCK ERROR: no convergence of Newton-Raphson iteration obtained"
      ENDIF
    !
    !*       2.1  calculate derivative F for next iteration
    !
      CALL CH_FCN(PTSIMUL+PDTACT,PNEWCONC,ZF,KMI,KVECNPT,KEQ)
      
      ZFTRAPEZVECT(:,:) = PNEWCONC(:,:) - ZYN(:,:)  - (1.0-PALPHA)*PDTACT*ZF(:,:)
    !
    !*       2.2  calculate the Jacobien B
    !
      CALL CH_JAC(PTSIMUL+PDTACT,PNEWCONC,ZBVECT,KMI,KVECNPT,KEQ)
    !
    !*       2.3  modify JAC after Cranck-Nicholson method
    !
      ZBVECT(:,:,:) = -(1.0-PALPHA)*PDTACT*ZBVECT(:,:,:)
      DO JI = 1, KEQ
        ZBVECT(:,JI,JI) = 1.0 + ZBVECT(:,JI,JI)
      ENDDO
    !
    !%kloos%
    ! Modification of matrix inversion (25/04/97)
    !
    !*       2.4 calculate LU factorization for ZB (result is put in ZB) 
    !
      DO JI=1,KVECNPT
      
      ZB(:,:)=ZBVECT(JI,:,:)
      ZFTRAPEZ(:)=ZFTRAPEZVECT(JI,:)
      
      IFAIL = 1
      CALL CH_GAUSS(ZB,ZC,KEQ,IFAIL)
      IF (IFAIL.NE.0) THEN
    !callabortstop
              CALL ABORT
        STOP 'CH_CRANCK ERROR: matrix cannot be inverted by CH_GAUSS'
      ENDIF
    !
    !*       2.5  calculate dY = ZB F (result is put in ZFTRAPEZ)
    !
      ZFTRAPEZ(:)=MATMUL(ZC(:,:),ZFTRAPEZ(:))
    !
    !*       2.6  calculate Y (n+1) 
    !
      ZERR(JI) = 0.0
      ZNORM = 0.0
      DO JJ=1,KEQ
        ZERR(JI) = ZERR(JI) + ABS(ZFTRAPEZ(JJ))
        PNEWCONC(JI,JJ) = PNEWCONC(JI,JJ) - ZFTRAPEZ(JJ)
        ZNORM = ZNORM + 0.5*ABS(PCONC(JI,JJ)+PNEWCONC(JI,JJ))
      ENDDO
    !%
      ZERR(JI) = ZERR(JI) / ZNORM
      
      ENDDO
    !
    END DO newton
    !
    END SUBROUTINE CH_CRANCK