Add files via upload
This commit is contained in:
477
code/adjoint/partition_adj.f
Normal file
477
code/adjoint/partition_adj.f
Normal file
@ -0,0 +1,477 @@
|
||||
!$Id: partition_adj.f,v 1.3 2012/05/09 22:31:56 nicolas Exp $
|
||||
!
|
||||
SUBROUTINE PARTITION_ADJ( STT_ADJ, STT, NTRACER, XNUMOL )
|
||||
!
|
||||
!******************************************************************************
|
||||
! Subroutine PARTITION_ADJ is the adjoint of the fwd routine PARTITION.
|
||||
! (dkh, 08/01/05)
|
||||
! Based on ADJ_PARTITION from the GCv6 adjoint (dkh, 07/31/09)
|
||||
!
|
||||
! Arguments as Input:
|
||||
! ============================================================================
|
||||
! (1 ) STT (REAL*8 ) : Tracer concentrations [kg/box]
|
||||
! (2 ) NTRACER (INTEGER) : Number of tracers
|
||||
! (3 ) XNUMOL (REAL*8 ) : Array of molecules tracer / kg tracer
|
||||
! (4 ) STT_ADJ (REAL*8 ) : Array of adjoint concentrations
|
||||
!
|
||||
! Arguments as Output:
|
||||
! ============================================================================
|
||||
! (1 ) STT_ADJ (REAL*8 ) : Updated adjoint concentrations
|
||||
!
|
||||
! NOTES:
|
||||
! (1 ) See fwd version for additional notes.
|
||||
! (2 ) Disable OMP parallel loops, which were leading to small errors
|
||||
! in the 7th digit. (dkh, 10/08/06)
|
||||
! (3 ) Update to GCv8 (dkh, 07/31/09)
|
||||
! (4 ) Tighten filter to 1d-10 (jkoo, dkh, boun, 05/08/12)
|
||||
!******************************************************************************
|
||||
!
|
||||
! References to F90 modules
|
||||
USE COMODE_MOD, ONLY : CSPEC, JLOP, VOLUME
|
||||
USE COMODE_MOD, ONLY : CSPEC_PRIOR, CSPEC_ADJ
|
||||
USE ERROR_MOD, ONLY : ALLOC_ERR, ERROR_STOP
|
||||
USE CHECKPT_MOD, ONLY : PART_CASE
|
||||
USE TRACERID_MOD
|
||||
|
||||
IMPLICIT NONE
|
||||
|
||||
# include "CMN_SIZE"
|
||||
# include "comode.h"
|
||||
|
||||
! Arguments
|
||||
INTEGER, INTENT(IN) :: NTRACER
|
||||
REAL*8, INTENT(INOUT) :: STT(IIPAR,JJPAR,LLPAR,NNPAR)
|
||||
REAL*8, INTENT(INOUT) :: STT_ADJ(IIPAR,JJPAR,LLPAR,NTRACER)
|
||||
REAL*8, INTENT(IN) :: XNUMOL(NNPAR)
|
||||
|
||||
! Local variables
|
||||
INTEGER :: I, J, L, N, JLOOP, IPL, JJ, KK
|
||||
INTEGER :: CSAVEID(IGAS)
|
||||
INTEGER :: CSAVEID_JJ(IGAS)
|
||||
INTEGER :: CS, IDNUM, AS
|
||||
REAL*8 :: CONCTMP, CONCNOX, SUM, SUM1
|
||||
REAL*8 :: CSAVE( ITLOOP, IGAS )
|
||||
! UPDATE: Add this so we don't overwrite CSPEC. (dkh, 10/10/08)
|
||||
REAL*8 :: CSPEC_TMP(IGAS)
|
||||
|
||||
|
||||
! Adjoint varialbes
|
||||
INTEGER :: NN
|
||||
REAL*8 :: ADCONCNOX
|
||||
REAL*8 :: ADCONCTMP
|
||||
REAL*8 :: ADSUM, ADSUM1
|
||||
REAL*8 :: ADCSAVE( ITLOOP, IGAS )
|
||||
|
||||
|
||||
!=================================================================
|
||||
! PARTITION_ADJ begins here!
|
||||
!=================================================================
|
||||
|
||||
! Move this to further down below so that it happens every time
|
||||
! through the loop. (dkh, 10/10/08)
|
||||
!! Reset local adjoint variables to zero
|
||||
!ADSUM = 0.d0
|
||||
!ADSUM1 = 0.d0
|
||||
!ADCONCNOX = 0.d0
|
||||
!ADCONCTMP = 0.d0
|
||||
|
||||
ADCSAVE(:,:) = 0.d0
|
||||
|
||||
|
||||
! Copy values of CSPEC that need to be saved (bdf, 3/30/99)
|
||||
!=================================================================
|
||||
IDNUM = 0
|
||||
|
||||
DO N = 1, NTRACER
|
||||
|
||||
! Skip if this is not a valid tracer
|
||||
IF ( IDTRMB(N,1) == 0 ) CYCLE
|
||||
|
||||
! Handle all other tracers except Ox
|
||||
IF ( N /= IDTOX ) THEN
|
||||
DO KK = 1, NMEMBER(N)
|
||||
IDNUM = IDNUM + 1
|
||||
JJ = IDTRMB(N,KK)
|
||||
CSAVEID(JJ) = IDNUM
|
||||
CSAVEID_JJ(IDNUM) = JJ
|
||||
ENDDO
|
||||
|
||||
! Handle Ox
|
||||
ELSE IF ( IDTOX /= 0 ) THEN
|
||||
JJ = IDTRMB(N,1)
|
||||
IDNUM = IDNUM + 1
|
||||
CSAVEID(JJ) = IDNUM
|
||||
CSAVEID_JJ(IDNUM) = JJ
|
||||
|
||||
ENDIF
|
||||
ENDDO
|
||||
|
||||
! Loop over tracer members and boxes
|
||||
!$OMP PARALLEL DO
|
||||
!$OMP+DEFAULT( SHARED )
|
||||
!$OMP+PRIVATE( I, J, L, N, JLOOP )
|
||||
!$OMP+SCHEDULE( DYNAMIC )
|
||||
DO N = 1, IDNUM
|
||||
DO L = 1, NPVERT
|
||||
DO J = 1, NLAT
|
||||
DO I = 1, NLONG
|
||||
|
||||
! 1-D SMVGEAR grid box index
|
||||
JLOOP = JLOP(I,J,L)
|
||||
IF ( JLOOP == 0 ) CYCLE
|
||||
|
||||
! Store into CSAVE
|
||||
CSAVE(JLOOP,N) = CSPEC(JLOOP,CSAVEID_JJ(N))
|
||||
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
!$OMP END PARALLEL DO
|
||||
|
||||
!=================================================================
|
||||
! Split each tracer up into its components (if any)
|
||||
! Family tracers are partitioned among members according to
|
||||
! initial ratios. In tracer sequence, OX must be after NOX,
|
||||
! otherwise, adjust the code
|
||||
!=================================================================
|
||||
|
||||
! BUG FIX: Loop from NTRACER to 1 by -1. (dkh, 10/10/08)
|
||||
! OLD CODE:
|
||||
!DO N = 1, NTRACER
|
||||
! NEW CODE:
|
||||
DO N = NTRACER, 1, -1
|
||||
|
||||
! Get STT_ADJ tracer ID
|
||||
!NN = ADJ2STT(N)
|
||||
NN = N
|
||||
|
||||
! Skip if it's not a valid tracer
|
||||
IF ( IDTRMB(N,1) == 0 .OR. NN == 0 ) CYCLE
|
||||
|
||||
!### Debug
|
||||
!WRITE(6,*) 'IN PARTITION N= ', N
|
||||
|
||||
! Loop over grid boxes
|
||||
! UPDATE: reinstate OMP parallelization here (dkh, 10/11/08)
|
||||
!$OMP PARALLEL DO
|
||||
!$OMP+DEFAULT( SHARED )
|
||||
!$OMP+PRIVATE( I, J, L, JLOOP, CONCTMP, SUM, KK, JJ, SUM1, CONCNOX )
|
||||
!$OMP+PRIVATE( ADCONCTMP, ADCONCNOX, ADSUM, ADSUM1 )
|
||||
!$OMP+SCHEDULE( DYNAMIC )
|
||||
DO L = 1, NPVERT
|
||||
DO J = 1, NLAT
|
||||
DO I = 1, NLONG
|
||||
|
||||
! BUG FIX: Reset adjoint variables here. (dkh, 10/10/08)
|
||||
! Reset local adjoint variables to zero
|
||||
ADSUM = 0.d0
|
||||
ADSUM1 = 0.d0
|
||||
ADCONCNOX = 0.d0
|
||||
ADCONCTMP = 0.d0
|
||||
|
||||
! 1-D SMVGEAR grid box index
|
||||
JLOOP = JLOP(I,J,L)
|
||||
IF ( JLOOP == 0 ) CYCLE
|
||||
|
||||
! Update: don't overwrite STT here (dkh, 10/10/08)
|
||||
! OLD:
|
||||
! Convert tracer concentration from [kg/box] to [molec/cm3/box]
|
||||
!STT(I,J,L,N) = STT(I,J,L,N) / VOLUME(JLOOP) * XNUMOL(N)
|
||||
!
|
||||
! Store concentration in CONCTMP
|
||||
!CONCTMP = STT(I,J,L,N)
|
||||
! NEW:
|
||||
CONCTMP = STT(I,J,L,N) / VOLUME(JLOOP) * XNUMOL(N)
|
||||
|
||||
|
||||
! Adjoint depends on which family was partitioned first, Ox or NOx
|
||||
SELECT CASE ( PART_CASE(JLOOP) )
|
||||
|
||||
! Partition NOx first
|
||||
CASE ( 1 )
|
||||
|
||||
!===========================================================
|
||||
! First, find sum of starting concentrations
|
||||
!===========================================================
|
||||
|
||||
!------------------------
|
||||
! All tracers except Ox
|
||||
!------------------------
|
||||
IF ( N /= IDTOX ) THEN
|
||||
SUM = 0.d0
|
||||
|
||||
DO KK = 1, NMEMBER(N)
|
||||
JJ = IDTRMB(N, KK)
|
||||
|
||||
! Error check
|
||||
IF ( JJ == 0 ) THEN
|
||||
PRINT *,JJ,JLOOP,N,KK,IDTRMB(N, KK)
|
||||
ENDIF
|
||||
|
||||
SUM = SUM
|
||||
& + CSAVE(JLOOP,CSAVEID(JJ)) * (CTRMB(N,KK)+1)
|
||||
ENDDO
|
||||
ENDIF
|
||||
|
||||
! Begin TAMC generated adjoint code. Manual modifications
|
||||
! are capitalized.
|
||||
if (n .ne. idtox) then
|
||||
do kk = 1, nmember(n)
|
||||
! Update: Avoid divide by sum**2,
|
||||
! which leads to NaNs (dkh, 10/10/08)
|
||||
IF ( SUM .GT. 1d-10 ) THEN
|
||||
jj = idtrmb(n,kk)
|
||||
adconctmp = adconctmp+cspec_adj(jloop,jj)*
|
||||
$(csave(jloop,csaveid(jj))/sum)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,
|
||||
$csaveid(jj))+cspec_adj(jloop,jj)/sum*conctmp
|
||||
adsum = adsum-cspec_adj(jloop,jj)*csave(jloop,
|
||||
$csaveid(jj))/(sum*sum)*conctmp
|
||||
ENDIF
|
||||
cspec_adj(jloop,jj) = 0.
|
||||
end do
|
||||
else if (idtox .ne. 0 .and. idtnox .ne. 0) then
|
||||
jj = ido3
|
||||
adconctmp = adconctmp+cspec_adj(jloop,jj)
|
||||
adsum1 = adsum1-cspec_adj(jloop,jj)
|
||||
cspec_adj(jloop,jj) = 0.
|
||||
else
|
||||
print*, ' big error here '
|
||||
endif
|
||||
if (n .ne. idtox) then
|
||||
do kk = 1, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,
|
||||
$csaveid(jj))+adsum*(1+ctrmb(n,kk))
|
||||
end do
|
||||
adsum = 0.
|
||||
else if (idtox .ne. 0) then
|
||||
do kk = 2, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
cspec_adj(jloop,jj) = cspec_adj(jloop,jj)
|
||||
&+adsum1*(1+ctrmb(n,kk))
|
||||
end do
|
||||
adsum1 = 0.
|
||||
endif
|
||||
|
||||
! Partition Ox first
|
||||
CASE ( 2 )
|
||||
|
||||
!===========================================================
|
||||
! First, find sum of starting concentrations
|
||||
!===========================================================
|
||||
|
||||
!------------------------
|
||||
! All tracers except Ox
|
||||
!------------------------
|
||||
IF ( N /= IDTOX ) THEN
|
||||
SUM = 0.d0
|
||||
|
||||
DO KK = 1, NMEMBER(N)
|
||||
JJ = IDTRMB(N, KK)
|
||||
|
||||
! Error check
|
||||
IF ( JJ == 0 ) THEN
|
||||
PRINT *,JJ,JLOOP,N,KK,IDTRMB(N, KK)
|
||||
ENDIF
|
||||
|
||||
SUM = SUM
|
||||
& + CSAVE(JLOOP,CSAVEID(JJ)) * (CTRMB(N,KK)+1)
|
||||
ENDDO
|
||||
|
||||
!------------------------
|
||||
! Ox
|
||||
!------------------------
|
||||
ELSE IF ( IDTOX /= 0 ) THEN
|
||||
JJ = IDTRMB(N,1)
|
||||
SUM = CSAVE(JLOOP,CSAVEID(JJ)) * (CTRMB(N,1)+1)
|
||||
! Case 1 stuff. dkh
|
||||
! SUM1 = 0.d0
|
||||
|
||||
|
||||
! SUM = sum of starting values for all Ox species (incl. O3)
|
||||
! SUM1 = sum of new values for all Ox species except O3,
|
||||
! based on NOx partitioning
|
||||
DO KK = 2, NMEMBER(N)
|
||||
JJ = IDTRMB(N,KK)
|
||||
SUM = SUM
|
||||
& + CSAVE(JLOOP,CSAVEID(JJ))*(CTRMB(N,KK)+1)
|
||||
! Case 1 stuff. dkh
|
||||
! SUM1 = SUM1+ CSPEC(JLOOP,JJ) * (CTRMB(N,KK)+1)
|
||||
ENDDO
|
||||
|
||||
ENDIF
|
||||
|
||||
! Begin TAMC generated adjoint of partioning for Case 2
|
||||
if (n .ne. idtox) then
|
||||
do kk = 1, nmember(n)
|
||||
IF ( SUM .gt. 1d-10 ) THEN
|
||||
jj = idtrmb(n,kk)
|
||||
adconctmp = adconctmp+cspec_adj(jloop,jj)*
|
||||
$(csave(jloop,csaveid(jj))/sum)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,
|
||||
$csaveid(jj))+cspec_adj(jloop,jj)/sum*conctmp
|
||||
adsum = adsum-cspec_adj(jloop,jj)*csave(jloop,
|
||||
$csaveid(jj))/(sum*sum)*conctmp
|
||||
ENDIF
|
||||
cspec_adj(jloop,jj) = 0.
|
||||
end do
|
||||
else if (idtox .ne. 0 .and. idtnox .ne. 0) then
|
||||
do kk = 1, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
! Update: don't overwrite CSPEC (dkh, 10/10/08)
|
||||
!cspec(jloop,jj) = csave(jloop,csaveid(jj))/sum*
|
||||
CSPEC_TMP(jj) = csave(jloop,csaveid(jj))/sum*
|
||||
$conctmp
|
||||
end do
|
||||
sum = 0.d0
|
||||
sum1 = 0.d0
|
||||
do kk = 1, nmember(idtnox)
|
||||
jj = idtrmb(idtnox,kk)
|
||||
if (jj .eq. idno .or. jj .eq. idhno2) then
|
||||
sum = sum+csave(jloop,csaveid(jj))*(ctrmb(idtnox,kk)+1)
|
||||
else
|
||||
! Update: use CSPEC_TMP (dkh, 10/10/08)
|
||||
!sum1 = sum1+cspec(jloop,jj)*(ctrmb(idtnox,kk)+1)
|
||||
sum1 = sum1+CSPEC_TMP(jj)*(ctrmb(idtnox,kk)+1)
|
||||
endif
|
||||
end do
|
||||
!----------------------------------
|
||||
! BUG FIX: need to convert units
|
||||
! of concnox here (jkoo, dkh, 09/30/10)
|
||||
! old code:
|
||||
!concnox = stt(i,j,l,idtnox)
|
||||
! new code:
|
||||
concnox = stt(i,j,l,idtnox)
|
||||
& / VOLUME(JLOOP) * XNUMOL(IDTNOX)
|
||||
!----------------------------------
|
||||
do kk = 1, nmember(idtnox)
|
||||
jj = idtrmb(idtnox,kk)
|
||||
if (jj .eq. idno .or. jj .eq. idhno2) then
|
||||
!IF ( sum .gt. 0d0 ) THEN
|
||||
IF ( sum .gt. 1d-10 ) THEN
|
||||
adconcnox = adconcnox+cspec_adj(jloop,jj)
|
||||
&*(csave(jloop,csaveid(jj))/sum)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,csaveid(jj))+
|
||||
$cspec_adj(jloop,jj)/sum*(concnox-sum1)
|
||||
adsum = adsum-cspec_adj(jloop,jj)*csave(jloop,csaveid(jj))
|
||||
$/(sum*sum)
|
||||
$*(concnox-sum1)
|
||||
adsum1 = adsum1-cspec_adj(jloop,jj)*(csave(jloop,csaveid(jj))/sum)
|
||||
ENDIF
|
||||
cspec_adj(jloop,jj) = 0.
|
||||
endif
|
||||
end do
|
||||
STT_ADJ(i,j,l,idtnox) =
|
||||
& STT_ADJ(i,j,l,idtnox)+adconcnox
|
||||
adconcnox = 0.
|
||||
do kk = 1, nmember(idtnox)
|
||||
jj = idtrmb(idtnox,kk)
|
||||
if (jj .eq. idno .or. jj .eq. idhno2) then
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,csaveid(jj))+adsum*(1+
|
||||
$ctrmb(idtnox,kk))
|
||||
else
|
||||
cspec_adj(jloop,jj) = cspec_adj(jloop,jj)
|
||||
& +adsum1*(1+ctrmb(idtnox,kk))
|
||||
endif
|
||||
end do
|
||||
adsum1 = 0.
|
||||
adsum = 0.
|
||||
!sum = sumk
|
||||
if (n .ne. idtox) then
|
||||
sum = 0.d0
|
||||
do kk = 1, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
sum = sum+csave(jloop,csaveid(jj))*(ctrmb(n,kk)+1)
|
||||
end do
|
||||
else if (idtox .ne. 0) then
|
||||
jj = idtrmb(n,1)
|
||||
sum = csave(jloop,csaveid(jj))*(ctrmb(n,1)+1)
|
||||
do kk = 2, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
sum = sum+csave(jloop,csaveid(jj))*(ctrmb(n,kk)+1)
|
||||
end do
|
||||
endif
|
||||
do kk = 1, nmember(n)
|
||||
!IF ( sum .gt. 0d0 ) THEN
|
||||
IF ( sum .gt. 1d-10 ) THEN
|
||||
jj = idtrmb(n,kk)
|
||||
adconctmp = adconctmp+cspec_adj(jloop,jj)*
|
||||
$(csave(jloop,csaveid(jj))/sum)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,
|
||||
$csaveid(jj))+cspec_adj(jloop,jj)/sum*conctmp
|
||||
adsum = adsum-cspec_adj(jloop,jj)*csave(jloop,
|
||||
$csaveid(jj))/(sum*sum)*conctmp
|
||||
ENDIF
|
||||
cspec_adj(jloop,jj) = 0.
|
||||
end do
|
||||
endif
|
||||
if (n .ne. idtox) then
|
||||
do kk = 1, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,
|
||||
$csaveid(jj))+adsum*(1+ctrmb(n,kk))
|
||||
end do
|
||||
adsum = 0.
|
||||
else if (idtox .ne. 0) then
|
||||
do kk = 2, nmember(n)
|
||||
jj = idtrmb(n,kk)
|
||||
adcsave(jloop,csaveid(jj)) = adcsave(jloop,
|
||||
$csaveid(jj))+adsum*(1+ctrmb(n,kk))
|
||||
end do
|
||||
jj = idtrmb(n,1)
|
||||
adcsave(jloop,csaveid(jj)) =
|
||||
$adcsave(jloop,csaveid(jj))+adsum*(1+ctrmb(n,1))
|
||||
adsum = 0.
|
||||
endif
|
||||
|
||||
CASE DEFAULT
|
||||
WRITE(6,*) I, J, L, JLOOP
|
||||
CALL ERROR_STOP( 'bad PART_CASE', 'PARTITION_ADJ' )
|
||||
|
||||
END SELECT
|
||||
|
||||
STT_ADJ(i,j,l,NN) = STT_ADJ(i,j,l,NN)+adconctmp
|
||||
adconctmp = 0.
|
||||
STT_ADJ(i,j,l,NN) = STT_ADJ(i,j,l,NN)
|
||||
& /volume(jloop)*xnumol(n)
|
||||
|
||||
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
!$OMP END PARALLEL DO
|
||||
ENDDO
|
||||
|
||||
! BUG FIX: add this part to pass sensitivities to ADJ_CSPEC
|
||||
! which then get fed back to STT_ADJ in subroutine LUMP_ADJ
|
||||
! (dkh, 10/11/08)
|
||||
!$OMP PARALLEL DO
|
||||
!$OMP+DEFAULT( SHARED )
|
||||
!$OMP+PRIVATE( I, J, L, N, JLOOP )
|
||||
!$OMP+SCHEDULE( DYNAMIC )
|
||||
DO N = 1, IDNUM
|
||||
DO L = 1, NPVERT
|
||||
DO J = 1, NLAT
|
||||
DO I = 1, NLONG
|
||||
|
||||
! 1-D SMVGEAR grid box index
|
||||
JLOOP = JLOP(I,J,L)
|
||||
IF ( JLOOP == 0 ) CYCLE
|
||||
|
||||
! fwd code:
|
||||
!CSAVE(JLOOP,N) = CSPEC(JLOOP,CSAVEID_JJ(N))
|
||||
! adj code:
|
||||
CSPEC_ADJ(JLOOP,CSAVEID_JJ(N)) = CSPEC_ADJ(JLOOP,CSAVEID_JJ(N))
|
||||
& + ADCSAVE(JLOOP,N)
|
||||
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
!$OMP END PARALLEL DO
|
||||
|
||||
! Return to calling program
|
||||
END SUBROUTINE PARTITION_ADJ
|
||||
|
Reference in New Issue
Block a user