SUBROUTINE ice_carb_chem !------------------------------------------------------------------------------! ! *** ice_carb_chem *** ! ! This routine re-equilibrates the chemical species of the carbonate system ! given two variables (DIC and Alk, or CO2 and Alk) ! ! Original code: Zeebe and Wolf-Gladrow, 2001. CO2 in Seawater: ! Equilibrium, Kinetics, Isotopes. ! (http://www.soest.hawaii.edu/oceanography/faculty/zeebe_files/CO2_System_in_Seawater/csys.html) ! ! Translation in F90: S. Moreau, P.-Y Barriat, S. Dubinkina, June 2012 ! ! Rewriting: M. Vancopppenolle, S. Moreau, Dec 2015 ! ! - Remove dummy arrays for T and S (use t_i_bio and sbr_bio instead) ! - change the name of the routine ! - remove the obsolete declarations ! Present status : c_i_bio(13,*) is wrong... to be continued!! ! !------------------------------------------------------------------------------! USE lib_fortran INCLUDE 'type.com' INCLUDE 'para.com' INCLUDE 'const.com' INCLUDE 'ice.com' INCLUDE 'thermo.com' INCLUDE 'bio.com' EXTERNAL zgeev ! lapack (computes the eigenvalues of complex nonsymmetric matrix) REAL(8), DIMENSION(nlay_bio) :: & Kw, !: Equilibrium constants & Kh, & Kb, & Ks, & Kf, & K1, & K2 REAL(8) :: ! define local variables & h1, & ztmp, & ztmp1, & ztmp2, & ztmp3, & ztmp4, & zbor, & zT, & z1T, & zlogT, & zT2, & zT3, & ztc, & ztc2, & ztc3, & zS12, & zS, & zS32, & zS2, & zhp LOGICAL :: & ln_write_bio = .TRUE. REAL(8), DIMENSION(6) :: & zpoly INTEGER(4), PARAMETER :: ! Parameters for H+ retrieval & n_hp = 5 ! size of the polynom REAL(8) :: & zb5(2,0:n_hp), & zrwrk(2*n_hp) INTEGER(4) & zinfo ! COMPLEX(16) :: DOUBLE COMPLEX :: & zA(n_hp+1,n_hp+1), & zvl(n_hp,n_hp), & zvr(n_hp,n_hp), & zwrk(3*n_hp), & zeigs(n_hp) !==============================================================================! IF ( ln_write_bio ) THEN WRITE(numout,*) WRITE(numout,*) ' ice_carb_chem ' WRITE(numout,*) '~~~~~~~~~~~~~~~' WRITE(numout,*) ENDIF CALL ice_brine DO layer = 1, nlay_bio !------------------------------------------------------------ ! 1) Physical inputs (temperature and brine salinity) !------------------------------------------------------------ ! temperature factors zT = t_i_bio(layer) z1t = 1.d0/zT zlogT = LOG(zT) zT2 = zT*zT ! Brine salinity factors ztc = tc_bio(layer) ztc2 = ztc*ztc ztc3 = ztc2 * ztc zS12 = SQRT(sbr_bio(layer)) zS = sbr_bio(layer) zS32 = zS12*zS zS2 = zS*zS !---------------------------------------------------------------- ! 2) Equilibrium constants !---------------------------------------------------------------- ! ! units: mol/kg-soln ! set phflag (0:Total), (1:Free) !--- Kw (water dissociation constant) !-------------------------------------- ! ! Millero (1995)(in Dickson and Goyet (1994, Chapter 5, p.18)) ! K_w in mol/kg-soln. ! pH-scale: total scale. ztmp1 = -13847.26*z1T + 148.96502 - 23.6521*zlogT ztmp2 = ( 118.67*z1T - 5.977 + 1.0495*zlogT)*zs12 - 0.01615*zS ztmp = ztmp1 + ztmp2 Kw(layer) = EXP(ztmp) !--- Kh (Henry's solubility) !---------------------------- ! ! CO2(g) <-> CO2(aq.) ! Kh = [CO2]/ p CO2 ! ! Weiss (1974) [mol/kg/atm] ! ztmp = 9345.17*z1t - 60.2409 + 23.3585*(zlogt - LOG(100.)) ztmp = ztmp + zS*( 0.023517 - 2.3656e-4*zT + 4.7036e-7*zT2 ) Kh(layer) = EXP(ztmp) !--- K1 (first acidity constant) !-------------------------------- ! [H+].[HCO3-]/[CO2] = K1 IF ( nn_carbonate .EQ. 1 ) THEN ! Roy et al. (1993) IN: Dickson and Goyet (1994), Ch. 5, p. 14 ! pH-scale: 'total'. mol/kg-soln ztmp1 = 2.83655 - 2307.1266*z1t - & 1.5529413*zlogt ztmp2 = - ( 0.20760841 + 4.0484 *z1t ) * zs12 ztmp3 = 0.08468345*zS - 0.00654208*zS32 ztmp4 = LOG( 1. - 0.001005*zS ) ztmp = ztmp1 + ztmp2 + ztmp3 + ztmp4 K1(layer) = EXP(ztmp) ELSE ! Mehrbach et al (1973) refit by Lueker et al. (2000). ! pH-scale: 'total'. mol/kg-soln ztmp = 3633.86 * z1t - 61.2172 + 9.6777*zlogt - & 0.011555*zS + 0.0001152*zS2 K1(layer) = 10**(-ztmp) ENDIF !--- K2 (second acidity constant) !--------------------------------- ! [H+].[CO32-]/[HCO3-] = K2 IF ( nn_carbonate .EQ. 1 ) THEN ! Roy et al 1993, total ph-scale mol/kg-soln ztmp1 = - 9.226508 - 3351.6106*z1t - 0.2005743*zlogt ztmp2 = ( -0.106901773 - 23.9722*z1t ) * zs12 ztmp3 = 0.1130822*zs - 8.46934e-3*zs32 + LOG(1.-1.005e-3*zS) ztmp = ztmp1 + ztmp2 + ztmp3 K2(layer) = EXP(ztmp) ELSE ! Mehrbach et al. (1973) refit by Lueker et al. (2000). ztmp = 471.78*z1T + 25.9290 - & 3.16967*zlogT - & 0.01781*zS + 0.0001122*zS2 K2(layer) = 10**(-ztmp) ENDIF !--- KB (Boron dissociation constant) !------------------------------------- ! Kbor = [H+][B(OH)4-]/[B(OH)3] ! Dickson (1990), IN:Dickson and Goyet, 1994, Chapter 5, p. 14) ! pH-scale: 'total'. mol/kg-soln ztmp1 = ( -8966.90 - 2890.53*zs12 - 77.942 * zS + & 1.728*zS32 - 0.0996*zS2 ) ztmp2 = 148.0248 + 137.1942 * zs12 + 1.62142 * zS ztmp3 = (-24.4344 - 25.085*zs12 - 0.2474*zs)*zlogT ztmp = ztmp1 * z1t + ztmp2 + ztmp3 + 0.053105*zs12*zT Kb(layer) = EXP(ztmp) END DO ! layer IF ( ln_write_bio ) THEN WRITE(numout,*) WRITE(numout,*) ' Carbonate system constants ' WRITE(numout,*) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~' WRITE(numout,*) WRITE(numout,*) ' Kw :',( Kw(layer), layer=layer_00, nlay_bio ) WRITE(numout,*) WRITE(numout,*) ' Kh :',( Kh(layer), layer=layer_00, nlay_bio ) WRITE(numout,*) WRITE(numout,*) ' K1 :',( K1(layer), layer=layer_00, nlay_bio ) WRITE(numout,*) WRITE(numout,*) ' K2 :',( K2(layer), layer=layer_00, nlay_bio ) WRITE(numout,*) WRITE(numout,*) ' Kb :',( Kb(layer), layer=layer_00, nlay_bio ) ENDIF !------------------------------------------------------------------------ ! 3) Convert brine concentrations units (mmol/m3 -> mol/kg) !------------------------------------------------------------------------ ! mmol/m3 to mol/kg DO layer = 1, nlay_bio zunit = 1000. * rhobr_bio(layer) c_i_bio(jn_dic,layer) = & c_i_bio(jn_dic,layer) / zunit c_i_bio(jn_alk,layer) = & c_i_bio(jn_alk,layer) / zunit END DO ! Alk !------------------------------------------------------------------------ ! 4) Carbonate system equilibration !------------------------------------------------------------------------ DO layer = 1, nlay_bio !--- polynomial coefficients !---------------------------- zbor = 1.*(416.*(sbr_bio(layer)/35.))* 1.e-6 ! Total boron (mol/kg), DOE94 ! Compute the coefficients of the 5th order polynom for H+ ! -> Check Orr et al GMD 2015 and Munhoven et al., GBC2014 for more efficient computations ! poly = [p5 p4 p3 p2 p1 p0] ! test = p5 h⁵ + p4 h⁴ + p3 h³ + p2 h² + p1 h¹ + p0 zpoly(1) = - 1. ! p5 zpoly(2) = - c_i_bio(jn_alk,layer) - ! p4 & Kb(layer) - K1(layer) zpoly(3) = c_i_bio(jn_dic,layer)*K1(layer) - ! p3 & c_i_bio(jn_alk,layer)*( Kb(layer) + K1(layer) ) + & Kb(layer)*zbor + Kw(layer) - & Kb(layer)*K1(layer) - K1(layer)*K2(layer) ztmp = c_i_bio(jn_alk,layer)*( Kb(layer)*K1(layer) + & 2.*K1(layer)*K2(layer)) - c_i_bio(jn_dic,layer)* & ( Kb(layer)*K1(layer) + K1(layer)*K2(layer) ) + & Kb(layer)*zbor*K1(layer) zpoly(4) = ztmp + Kw(layer)*Kb(layer) + ! p2 & Kw(layer)*K1(layer) - & Kb(layer)*K1(layer)*K2(layer) ztmp = ( 2.*c_i_bio(jn_dic,layer) - & c_i_bio(jn_alk,layer) + zbor)* & K1(layer)*K2(layer)*Kb(layer) zpoly(5) = ztmp + ( Kb(layer) + K2(layer) )* ! p1 & K1(layer)*Kw(layer) zpoly(6) = Kw(layer)*Kb(layer)*K1(layer)*K2(layer) ! p0 !--- find roots of the 5th degree monic polynomial !-------------------------------------------------- zb5(1,0:n_hp) = zpoly(:) zb5(2,:) = 0.d0 ! IF ( ln_write_bio ) THEN ! WRITE(numout,*) ! WRITE(numout,*) ' zb5 - 1 : ', zb5(1,0:n_hp) ! WRITE(numout,*) ' zb5 - 2 : ', zb5(2,0:n_hp) ! WRITE(numout,*) ! WRITE(numout,*) ' zpoly : ', zpoly ! WRITE(numout,*) ! ENDIF ! Setup companion matrix for polynomials DO i = 1, n_hp + 1 DO j = 1, n_hp + 1 IF ( j .EQ. n_hp+1 ) THEN zA(i,j) = -DCMPLX(zb5(1, n_hp+1-i),zb5(2,n_hp+1-i)) ELSE IF (J.EQ.I-1) THEN zA(i,j) = DCMPLX(1.d0,0.d0) ELSE zA(i,j) = DCMPLX(0.d0,0.d0) ENDIF END DO END DO ! IF ( ln_write_bio ) THEN ! WRITE(numout,*) ! WRITE(numout,*) ' zA : ', zA ! WRITE(numout,*) ! ENDIF ! Calculate eigenvalues of companion matrix (LAPACK) ! 'N' -> left eigen vectors are not computed ! 'N' -> right egien vectors are not computer ! n_hp+1 -> order of the matrix A ! A -> complex matrix, dimension (LDA, N) ! ->IN: complex NxN ! ->OUT: overwritten ! n_hp+1 -> leading dimension of A ! zeigs-> computed eigen values ! zvl -> dummy (unused here) left eigenvector ! n_hp + 1 -> dimension of eigen vector ! zvr -> dummy (unused here) left eigenvector ! n_hp + 1 -> dimension of right eigen vector ! zwrk, zrwrk -> workarray ! 3*n_hp+3 -> size of workarray ! zinfo -> =0 successful work CALL zgeev('N','N',n_hp+1,zA,n_hp+1,zeigs,zvl,n_hp+1, & zvr,n_hp+1,zwrk,3*n_hp+3,zrwrk,zinfo) zhp = MAXVAL( REAL ( zeigs ) ) ! Print eigenvalues of companion matrix (roots of the polynom) ! IF ( ln_write_bio ) THEN ! WRITE(numout,*) ! WRITE(numout,*) ' zinfo : ', zinfo ! WRITE(numout,*) ! WRITE(numout,*) ' zeigs :', ( zeigs(i), i = 1, n_hp ) ! WRITE(numout,*) ! WRITE(numout,*) ' zhp :', zhp ! WRITE(numout,*) ! WRITE(numout,*) ' pH : ', -LOG10( zhp ) ! WRITE(numout,*) ! WRITE(numout,*) ! ENDIF !--- Retrieve carbonate system diagnostics !-------------------------------------------------- zhp2 = zhp * zhp ! [H+]^2 c_i_bio(jn_co2, layer) = c_i_bio(jn_dic, layer) / ! CO2 & ( 1. + K1(layer) / zhp + & K1(layer)*K2(layer) / zhp2 ) CO2aq(layer) = c_i_bio(jn_co2,layer) !--- temporary as jn_co2 is bound to disappear CO32m(layer) = c_i_bio(jn_dic,layer) / ! CO32- & ( 1. + zhp / K2(layer) + & zhp2 / K1(layer) / K2(layer) ) HCO3m(layer) = c_i_bio(jn_dic,layer) / ! HCO3- & ( 1. + zhp / K1(layer) + & K2(layer) / zhp ) pH(layer) = -LOG10( zhp ) pCO2(layer) = CO2aq(layer) / Kh(layer) ! pCO2 = CO2aq / Kh END DO ! layer !------------------------------------------------------------------------ ! 5) Convert units (mol/kg to mmol/m3), retrieve bulk concentrations !------------------------------------------------------------------------ DO layer = 1, nlay_bio ! mol/kg -> mmol/m3 zunit = 1000. * rhobr_bio(layer) c_i_bio(jn_dic,layer) = c_i_bio(jn_dic,layer) * zunit !--- dont change DIC and TA, can remove c_i_bio(jn_alk,layer) = c_i_bio(jn_alk,layer) * zunit !--- dont change DIC and TA, can remove c_i_bio(jn_co2,layer) = c_i_bio(jn_co2,layer) * zunit CO2aq(layer) = CO2aq(layer) * zunit CO32m(layer) = CO32m(layer) * zunit HCO3m(layer) = HCO3m(layer) * zunit ! brine -> bulk cbu_i_bio(jn_co2,layer) = c_i_bio(jn_co2,layer)*e_i_bio(layer) CO2aq(layer) = CO2aq(layer)*e_i_bio(layer) CO32m(layer) = CO32m(layer)*e_i_bio(layer) HCO3m(layer) = HCO3m(layer)*e_i_bio(layer) ! atm-> muatm pCO2(layer) = pCO2(layer) * 1.0e6 END DO !------------------------------------------------------------------------ ! 6) Control Print !------------------------------------------------------------------------ IF ( ln_write_bio ) THEN WRITE(numout,*) WRITE(numout,*) ' ** End of ice_carb_chem ' WRITE(numout,*) ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' WRITE(numout,*) ' At time step : ', numit WRITE(numout,*) ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' WRITE(numout,*) DO jn = 1, ntra_bio IF ( ( jn .EQ. jn_dic ) .OR. ( jn .EQ. jn_alk ) .OR. & ( jn .EQ. jn_co2 ) ) THEN WRITE(numout,*) ' Tracer : ', biotr_i_nam(jn) WRITE(numout,*) ' c_i_bio : ', ( c_i_bio(jn,layer), & layer = 1, nlay_bio ) WRITE(numout,*) ' cbu_i_bio: ', ( cbu_i_bio(jn,layer), & layer = 1, nlay_bio ) ENDIF END DO WRITE(numout,*) ' CO2aq : ', & ( CO2aq(layer), layer = 1, nlay_bio ) WRITE(numout,*) ' CO32- : ', & ( CO32m(layer), layer = 1, nlay_bio ) WRITE(numout,*) ' HCO3- : ', & ( HCO3m(layer), layer = 1, nlay_bio ) WRITE(numout,*) ' pH : ', & ( pH(layer), layer = 1, nlay_bio ) WRITE(numout,*) ' pCO2 : ', & ( pCO2(layer), layer = 1, nlay_bio ) ENDIF ! !------------------------------------------------------------------------------! ! 7) End of the routine !------------------------------------------------------------------------------! ! WRITE(numout,*) WRITE(numout,*) ' End of ice_carb_chem ' WRITE(numout,*) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' RETURN END