MODULE observable_mod USE icosa IMPLICIT NONE PRIVATE TYPE(t_field),POINTER, SAVE :: f_buf_i(:), & f_buf_Fel(:), f_buf_uh(:), & ! horizontal velocity, different from prognostic velocity if NH f_buf_ulon(:), f_buf_ulat(:), & f_buf_u3d(:) ! unused, remove ? TYPE(t_field),POINTER, SAVE :: f_buf1_i(:), f_buf2_i(:) TYPE(t_field),POINTER, SAVE :: f_buf_v(:), f_buf_s(:), f_buf_p(:) TYPE(t_field),POINTER, SAVE :: f_pmid(:) ! temporary shared variable for caldyn TYPE(t_field),POINTER, SAVE :: f_theta(:) PUBLIC init_observable, write_output_fields_basic, f_theta CONTAINS SUBROUTINE init_observable CALL allocate_field(f_buf_i, field_t,type_real,llm,name="buffer_i") CALL allocate_field(f_buf1_i, field_t,type_real,llm,name="buffer1_i") CALL allocate_field(f_buf2_i, field_t,type_real,llm,name="buffer2_i") CALL allocate_field(f_buf_p, field_t,type_real,llm+1) CALL allocate_field(f_buf_u3d, field_t,type_real,3,llm) ! 3D vel at cell centers CALL allocate_field(f_buf_ulon,field_t,type_real,llm, name="buf_ulon") CALL allocate_field(f_buf_ulat,field_t,type_real,llm, name="buf_ulat") CALL allocate_field(f_buf_uh, field_u,type_real,llm, name="buf_uh") CALL allocate_field(f_buf_Fel, field_u,type_real,llm+1, name="buf_F_el") CALL allocate_field(f_buf_v, field_z,type_real,llm, name="buf_v") CALL allocate_field(f_buf_s, field_t,type_real, name="buf_s") CALL allocate_field(f_theta, field_t,type_real,llm,nqdyn, name='theta') ! potential temperature CALL allocate_field(f_pmid, field_t,type_real,llm, name='pmid') ! mid layer pressure END SUBROUTINE init_observable SUBROUTINE write_output_fields_basic(init, f_phis, f_ps, f_mass, f_geopot, f_theta_rhodz, f_u, f_W, f_q) USE xios_mod USE disvert_mod USE wind_mod USE output_field_mod USE omp_para USE time_mod USE xios_mod USE earth_const USE pression_mod USE vertical_interp_mod USE theta2theta_rhodz_mod USE omega_mod USE diagflux_mod LOGICAL, INTENT(IN) :: init INTEGER :: l REAL :: scalar(1) REAL :: mid_ap(llm) REAL :: mid_bp(llm) TYPE(t_field),POINTER :: f_phis(:), f_ps(:), f_mass(:), f_geopot(:), f_theta_rhodz(:), f_u(:), f_W(:), f_q(:) ! IF (is_master) PRINT *,'CALL write_output_fields_basic' CALL transfert_request(f_ps,req_i1) IF(init) THEN IF(is_master) PRINT *, 'Creating output files ...' scalar(1)=dt IF (is_omp_master) CALL xios_send_field("timestep", scalar) scalar(1)=preff IF (is_omp_master) CALL xios_send_field("preff", scalar) IF (is_omp_master) CALL xios_send_field("ap",ap) IF (is_omp_master) CALL xios_send_field("bp",bp) DO l=1,llm mid_ap(l)=(ap(l)+ap(l+1))/2 mid_bp(l)=(bp(l)+bp(l+1))/2 ENDDO IF (is_omp_master) CALL xios_send_field("mid_ap",mid_ap) IF (is_omp_master) CALL xios_send_field("mid_bp",mid_bp) CALL output_field("phis",f_phis) CALL output_field("Ai",geom%Ai) IF(is_master) PRINT *, '... done creating output files. Writing initial condition ...' END IF IF(nqdyn>1) THEN CALL divide_by_mass(2, f_mass, f_theta_rhodz, f_buf_i) IF(init) THEN CALL output_field("dyn_q_init",f_buf_i) ELSE CALL output_field("dyn_q",f_buf_i) END IF END IF CALL divide_by_mass(1, f_mass, f_theta_rhodz, f_buf_i) IF(init) THEN CALL output_field("theta_init",f_buf_i) ELSE CALL output_field("theta",f_buf_i) END IF CALL pression_mid(f_ps, f_pmid) CALL diagnose_temperature(f_pmid, f_q, f_buf_i) ! f_buf_i : IN = theta, out = T IF(init) THEN CALL output_field("temp_init",f_buf_i) ELSE CALL output_field("temp",f_buf_i) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,85000.) CALL output_field("t850",f_buf_s) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,50000.) CALL output_field("t500",f_buf_s) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,preff) CALL output_field("SST",f_buf_s) END IF CALL progonostic_vel_to_horiz(f_geopot, f_ps, f_mass, f_u, f_W, f_buf_uh, f_buf_i) CALL transfert_request(f_buf_uh,req_e1_vect) CALL un2ulonlat(f_buf_uh, f_buf_ulon, f_buf_ulat) IF(init) THEN CALL output_field("uz_init",f_buf_i) CALL output_field("ulon_init",f_buf_ulon) CALL output_field("ulat_init",f_buf_ulat) CALL output_field("p_init",f_pmid) CALL output_field("ps_init",f_ps) CALL output_field("mass_init",f_mass) CALL output_field("geopot_init",f_geopot) CALL output_field("q_init",f_q) IF(is_master) PRINT *, 'Done writing initial condition ...' ELSE CALL output_field("uz",f_buf_i) CALL output_field("ulon",f_buf_ulon) CALL output_field("ulat",f_buf_ulat) CALL output_field("p",f_pmid) CALL output_field("ps",f_ps) CALL output_field("mass",f_mass) CALL output_field("geopot",f_geopot) CALL output_field("q",f_q) ! CALL output_field("exner",f_pk) ! CALL output_field("pv",f_qv) CALL vertical_interp(f_pmid,f_buf_ulon,f_buf_s,85000.) CALL output_field("u850",f_buf_s) CALL vertical_interp(f_pmid,f_buf_ulon,f_buf_s,50000.) CALL output_field("u500",f_buf_s) CALL vertical_interp(f_pmid,f_buf_ulat,f_buf_s,85000.) CALL output_field("v850",f_buf_s) CALL vertical_interp(f_pmid,f_buf_ulat,f_buf_s,50000.) CALL output_field("v500",f_buf_s) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,85000.) CALL output_field("w850",f_buf_s) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,50000.) CALL output_field("w500",f_buf_s) CALL w_omega(f_ps, f_u, f_buf_i) CALL output_field("omega",f_buf_i) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,85000.) CALL output_field("omega850",f_buf_s) CALL vertical_interp(f_pmid,f_buf_i,f_buf_s,50000.) CALL output_field("omega500",f_buf_s) END IF IF(.NOT. init) THEN IF(diagflux_on) THEN CALL flux_centered_lonlat(1./(itau_out*dt) , f_massfluxt, f_buf_ulon, f_buf_ulat) CALL output_field("mass_t", f_masst) CALL output_field("massflux_lon",f_buf_ulon) CALL output_field("massflux_lat",f_buf_ulat) CALL flux_centered_lonlat(1./(itau_out*dt) , f_epotfluxt, f_buf_ulon, f_buf_ulat) CALL output_field("epot_t", f_epot) CALL output_field("epotflux_lon",f_buf_ulon) CALL output_field("epotflux_lat",f_buf_ulat) CALL flux_centered_lonlat(1./(itau_out*dt) , f_ekinfluxt, f_buf_ulon, f_buf_ulat) CALL output_field("ekin_t", f_ekin) CALL output_field("ekinflux_lon",f_buf_ulon) CALL output_field("ekinflux_lat",f_buf_ulat) CALL flux_centered_lonlat(1./(itau_out*dt) , f_enthalpyfluxt, f_buf_ulon, f_buf_ulat) CALL output_field("enthalpy_t", f_enthalpy) CALL output_field("enthalpyflux_lon",f_buf_ulon) CALL output_field("enthalpyflux_lat",f_buf_ulat) CALL qflux_centered_lonlat(1./(itau_out*dt) , f_qfluxt, f_qfluxt_lon, f_qfluxt_lat) CALL output_field("qmass_t", f_qmasst) CALL output_field("qflux_lon",f_qfluxt_lon) CALL output_field("qflux_lat",f_qfluxt_lat) CALL zero_qfluxt ! restart accumulating fluxes END IF END IF END SUBROUTINE write_output_fields_basic !------------------- Conversion from prognostic to observable variables ------------------ SUBROUTINE progonostic_vel_to_horiz(f_geopot, f_ps, f_rhodz, f_u, f_W, f_uh, f_uz) USE disvert_mod TYPE(t_field), POINTER :: f_geopot(:), f_ps(:), f_rhodz(:), & f_u(:), f_W(:), f_uz(:), & ! IN f_uh(:) ! OUT REAL(rstd),POINTER :: geopot(:,:), ps(:), rhodz(:,:), u(:,:), W(:,:), uh(:,:), uz(:,:), F_el(:,:) INTEGER :: ind DO ind=1,ndomain IF (.NOT. assigned_domain(ind)) CYCLE CALL swap_dimensions(ind) CALL swap_geometry(ind) geopot = f_geopot(ind) rhodz = f_rhodz(ind) u = f_u(ind) W = f_W(ind) uh = f_uh(ind) F_el = f_buf_Fel(ind) IF(caldyn_eta==eta_mass) THEN ps=f_ps(ind) CALL compute_rhodz(.TRUE., ps, rhodz) END IF uz = f_uz(ind) !$OMP BARRIER CALL compute_prognostic_vel_to_horiz(geopot,rhodz,u,W, F_el, uh,uz) !$OMP BARRIER END DO END SUBROUTINE progonostic_vel_to_horiz SUBROUTINE compute_prognostic_vel_to_horiz(Phi, rhodz, u, W, F_el, uh, uz) USE omp_para REAL(rstd), INTENT(IN) :: Phi(iim*jjm,llm+1) REAL(rstd), INTENT(IN) :: rhodz(iim*jjm,llm) REAL(rstd), INTENT(IN) :: u(3*iim*jjm,llm) REAL(rstd), INTENT(IN) :: W(iim*jjm,llm+1) REAL(rstd), INTENT(OUT) :: uh(3*iim*jjm,llm) REAL(rstd), INTENT(OUT) :: uz(iim*jjm,llm) INTEGER :: ij,l REAL(rstd) :: F_el(3*iim*jjm,llm+1) REAL(rstd) :: uu_right, uu_lup, uu_ldown, W_el, DePhil ! NB : u and uh are not in DEC form, they are normal components ! => we must divide by de IF(hydrostatic) THEN uh(:,:)=u(:,:) uz(:,:)=0. ELSE DO l=ll_begin, ll_endp1 ! compute on l levels (interfaces) DO ij=ij_begin_ext, ij_end_ext ! Compute on edge 'right' W_el = .5*( W(ij,l)+W(ij+t_right,l) ) DePhil = ne_right*(Phi(ij+t_right,l)-Phi(ij,l)) F_el(ij+u_right,l) = DePhil*W_el/de(ij+u_right) ! Compute on edge 'lup' W_el = .5*( W(ij,l)+W(ij+t_lup,l) ) DePhil = ne_lup*(Phi(ij+t_lup,l)-Phi(ij,l)) F_el(ij+u_lup,l) = DePhil*W_el/de(ij+u_lup) ! Compute on edge 'ldown' W_el = .5*( W(ij,l)+W(ij+t_ldown,l) ) DePhil = ne_ldown*(Phi(ij+t_ldown,l)-Phi(ij,l)) F_el(ij+u_ldown,l) = DePhil*W_el/de(ij+u_ldown) END DO END DO ! We need a barrier here because we compute F_el above and do a vertical average below !$OMP BARRIER DO l=ll_begin, ll_end ! compute on k levels (full levels) DO ij=ij_begin_ext, ij_end_ext ! w = vertical momentum = g^-2*dPhi/dt = uz/g uz(ij,l) = (.5*g)*(W(ij,l)+W(ij,l+1))/rhodz(ij,l) ! uh = u-w.grad(Phi) = u - uz.grad(z) uh(ij+u_right,l) = u(ij+u_right,l) - (F_el(ij+u_right,l)+F_el(ij+u_right,l+1)) / (rhodz(ij,l)+rhodz(ij+t_right,l)) uh(ij+u_lup,l) = u(ij+u_lup,l) - (F_el(ij+u_lup,l)+F_el(ij+u_lup,l+1)) / (rhodz(ij,l)+rhodz(ij+t_lup,l)) uh(ij+u_ldown,l) = u(ij+u_ldown,l) - (F_el(ij+u_ldown,l)+F_el(ij+u_ldown,l+1)) / (rhodz(ij,l)+rhodz(ij+t_ldown,l)) END DO END DO END IF END SUBROUTINE compute_prognostic_vel_to_horiz SUBROUTINE diagnose_temperature(f_pmid,f_q,f_temp) USE icosa USE pression_mod IMPLICIT NONE TYPE(t_field), POINTER :: f_pmid(:) ! IN TYPE(t_field), POINTER :: f_q(:) ! IN TYPE(t_field), POINTER :: f_temp(:) ! INOUT REAL(rstd), POINTER :: pmid(:,:) REAL(rstd), POINTER :: q(:,:,:) REAL(rstd), POINTER :: temp(:,:) INTEGER :: ind DO ind=1,ndomain IF (.NOT. assigned_domain(ind)) CYCLE CALL swap_dimensions(ind) CALL swap_geometry(ind) pmid=f_pmid(ind) q=f_q(ind) temp=f_temp(ind) CALL compute_diagnose_temp(pmid,q,temp) END DO END SUBROUTINE diagnose_temperature SUBROUTINE compute_diagnose_temp(pmid,q,temp) USE omp_para USE pression_mod REAL(rstd),INTENT(IN) :: pmid(iim*jjm,llm) REAL(rstd),INTENT(IN) :: q(iim*jjm,llm,nqtot) REAL(rstd),INTENT(INOUT) :: temp(iim*jjm,llm) REAL(rstd) :: Rd, p_ik, theta_ik, temp_ik, qv, chi, Rmix INTEGER :: ij,l Rd = kappa*cpp DO l=ll_begin,ll_end DO ij=ij_begin,ij_end p_ik = pmid(ij,l) theta_ik = temp(ij,l) qv = q(ij,l,1) ! water vaper mixing ratio = mv/md SELECT CASE(caldyn_thermo) CASE(thermo_theta) temp_ik = theta_ik*((p_ik/preff)**kappa) CASE(thermo_entropy) temp_ik = Treff*exp((theta_ik + Rd*log(p_ik/preff))/cpp) CASE(thermo_moist) Rmix = Rd+qv*Rv chi = ( theta_ik + Rmix*log(p_ik/preff) ) / (cpp + qv*cppv) ! log(T/Treff) temp_ik = Treff*exp(chi) END SELECT IF(physics_thermo==thermo_fake_moist) temp_ik=temp_ik/(1+0.608*qv) temp(ij,l)=temp_ik END DO END DO END SUBROUTINE compute_diagnose_temp SUBROUTINE Tv2T(f_Tv, f_q, f_T) TYPE(t_field), POINTER :: f_TV(:) TYPE(t_field), POINTER :: f_q(:) TYPE(t_field), POINTER :: f_T(:) REAL(rstd),POINTER :: Tv(:,:), q(:,:,:), T(:,:) INTEGER :: ind DO ind=1,ndomain IF (.NOT. assigned_domain(ind)) CYCLE CALL swap_dimensions(ind) CALL swap_geometry(ind) Tv=f_Tv(ind) T=f_T(ind) SELECT CASE(physics_thermo) CASE(thermo_dry) T=Tv CASE(thermo_fake_moist) q=f_q(ind) T=Tv/(1+0.608*q(:,:,1)) END SELECT END DO END SUBROUTINE Tv2T SUBROUTINE divide_by_mass(iq, f_mass, f_theta_rhodz, f_theta) INTEGER, INTENT(IN) :: iq TYPE(t_field), POINTER :: f_mass(:), f_theta_rhodz(:), f_theta(:) REAL(rstd), POINTER :: mass(:,:), theta_rhodz(:,:,:), theta(:,:) INTEGER :: ind DO ind=1,ndomain IF (.NOT. assigned_domain(ind)) CYCLE CALL swap_dimensions(ind) CALL swap_geometry(ind) mass=f_mass(ind) theta_rhodz=f_theta_rhodz(ind) theta=f_theta(ind) theta(:,:) = theta_rhodz(:,:,iq) / mass(:,:) END DO END SUBROUTINE divide_by_mass END MODULE observable_mod