!> @file chemistry_model_mod.f90 !------------------------------------------------------------------------------! ! This file is part of the PALM model system. ! ! PALM is free software: you can redistribute it and/or modify it under the ! terms of the GNU General Public License as published by the Free Software ! Foundation, either version 3 of the License, or (at your option) any later ! version. ! ! PALM is distributed in the hope that it will be useful, but WITHOUT ANY ! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ! A PARTICULAR PURPOSE. See the GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License along with ! PALM. If not, see . ! ! Copyright 2017-2018 Leibniz Universitaet Hannover ! Copyright 2017-2018 Karlsruhe Institute of Technology ! Copyright 2017-2018 Freie Universitaet Berlin !------------------------------------------------------------------------------! ! ! Current revisions: ! ----------------- ! ! ! Former revisions: ! ----------------- ! $Id: chemistry_model_mod.f90 3449 2018-10-29 19:36:56Z eckhard $ ! additional output - merged from branch resler ! ! 3438 2018-10-28 19:31:42Z pavelkrc ! Add terrain-following masked output ! ! 3373 2018-10-18 15:25:56Z kanani ! Remove MPI_Abort, replace by message ! ! 3318 2018-10-08 11:43:01Z sward ! Fixed faulty syntax of message string ! ! 3298 2018-10-02 12:21:11Z kanani ! Add remarks (kanani) ! Merge with trunk, replaced cloud_physics by bulk_cloud_model 28.09.2018 forkel ! Subroutines header and chem_check_parameters added 25.09.2018 basit ! Removed chem_emission routine now declared in chem_emissions.f90 30.07.2018 ERUSSO ! Introduced emissions namelist parameters 30.07.2018 ERUSSO ! ! Timestep steering added in subroutine chem_integrate_ij and ! output of chosen solver in chem_parin added 30.07.2018 ketelsen ! ! chem_check_data_output_pr: added unit for PM compounds 20.07.2018 forkel ! replaced : by nzb+1:nzt for pt,q,ql (found by kk) 18.07.2018 forkel ! debugged restart run for chem species 06.07.2018 basit ! reorganized subroutines in alphabetical order. 27.06.2018 basit ! subroutine chem_parin updated for profile output 27.06.2018 basit ! Added humidity arrays to USE section and tmp_qvap in chem_integrate 26.6.2018 forkel ! Merged chemistry with with trunk (nzb_do and nzt_do in 3d output) 26.6.2018 forkel ! ! reorganized subroutines in alphabetical order. basit 22.06.2018 ! subroutine chem_parin updated for profile output basit 22.06.2018 ! subroutine chem_statistics added ! subroutine chem_check_data_output_pr add 21.06.2018 basit ! subroutine chem_data_output_mask added 20.05.2018 basit ! subroutine chem_data_output_2d added 20.05.2018 basit ! subroutine chem_statistics added 04.06.2018 basit ! subroutine chem_emissions: Set cssws to zero before setting values 20.03.2018 forkel ! subroutine chem_emissions: Introduced different conversion factors ! for PM and gaseous compounds 15.03.2018 forkel ! subroutine chem_emissions updated to take variable number of chem_spcs and ! emission factors. 13.03.2018 basit ! chem_boundary_conds_decycle improved. 05.03.2018 basit ! chem_boundary_conds_decycle subroutine added 21.02.2018 basit ! chem_init_profiles subroutines re-activated after correction 21.02.2018 basit ! ! ! 3293 2018-09-28 12:45:20Z forkel ! Modularization of all bulk cloud physics code components ! ! 3248 2018-09-14 09:42:06Z sward ! Minor formating changes ! ! 3246 2018-09-13 15:14:50Z sward ! Added error handling for input namelist via parin_fail_message ! ! 3241 2018-09-12 15:02:00Z raasch ! +nest_chemistry ! ! 3209 2018-08-27 16:58:37Z suehring ! Rename flags indicating outflow boundary conditions ! ! 3182 2018-07-27 13:36:03Z suehring ! Revise output of surface quantities in case of overhanging structures ! ! 3045 2018-05-28 07:55:41Z Giersch ! error messages revised ! ! 3014 2018-05-09 08:42:38Z maronga ! Bugfix: nzb_do and nzt_do were not used for 3d data output ! ! 3004 2018-04-27 12:33:25Z Giersch ! Comment concerning averaged data output added ! ! 2932 2018-03-26 09:39:22Z maronga ! renamed chemistry_par to chemistry_parameters ! ! 2894 2018-03-15 09:17:58Z Giersch ! Calculations of the index range of the subdomain on file which overlaps with ! the current subdomain are already done in read_restart_data_mod, ! chem_last_actions was renamed to chem_wrd_local, chem_read_restart_data was ! renamed to chem_rrd_local, chem_write_var_list was renamed to ! chem_wrd_global, chem_read_var_list was renamed to chem_rrd_global, ! chem_skip_var_list has been removed, variable named found has been ! introduced for checking if restart data was found, reading of restart strings ! has been moved completely to read_restart_data_mod, chem_rrd_local is already ! inside the overlap loop programmed in read_restart_data_mod, todo list has ! bees extended, redundant characters in chem_wrd_local have been removed, ! the marker *** end chemistry *** is not necessary anymore, strings and their ! respective lengths are written out and read now in case of restart runs to ! get rid of prescribed character lengths ! ! 2815 2018-02-19 11:29:57Z suehring ! Bugfix in restart mechanism, ! rename chem_tendency to chem_prognostic_equations, ! implement vector-optimized version of chem_prognostic_equations, ! some clean up (incl. todo list) ! ! 2773 2018-01-30 14:12:54Z suehring ! Declare variables required for nesting as public ! ! 2772 2018-01-29 13:10:35Z suehring ! Bugfix in string handling ! ! 2768 2018-01-24 15:38:29Z kanani ! Shorten lines to maximum length of 132 characters ! ! 2766 2018-01-22 17:17:47Z kanani ! Removed preprocessor directive __chem ! ! 2756 2018-01-16 18:11:14Z suehring ! Fill values in 3D output introduced. ! ! 2718 2018-01-02 08:49:38Z maronga ! Initial revision ! ! ! ! ! Authors: ! -------- ! @author Renate Forkel ! @author Farah Kanani-Suehring ! @author Klaus Ketelsen ! @author Basit Khan ! ! !------------------------------------------------------------------------------! ! Description: ! ------------ !> Chemistry model for PALM-4U !> @todo Adjust chem_rrd_local to CASE structure of others modules. It is not !> allowed to use the chemistry model in a precursor run and additionally !> not using it in a main run !> @todo Update/clean-up todo list! (FK) !> @todo Set proper fill values (/= 0) for chem output arrays! (FK) !> @todo Add routine chem_check_parameters, add checks for inconsistent or !> unallowed parameter settings. !> CALL of chem_check_parameters from check_parameters. (FK) !> @todo Make routine chem_header available, CALL from header.f90 !> (see e.g. how it is done in routine lsm_header in !> land_surface_model_mod.f90). chem_header should include all setup !> info about chemistry parameter settings. (FK) !> @todo Implement turbulent inflow of chem spcs in inflow_turbulence. !> @todo Separate boundary conditions for each chem spcs to be implemented !> @todo Currently only total concentration are calculated. Resolved, parameterized !> and chemistry fluxes although partially and some completely coded but !> are not operational/activated in this version. bK. !> @todo slight differences in passive scalar and chem spcs when chem reactions !> turned off. Need to be fixed. bK !> @todo test nesting for chem spcs, was implemented by suehring (kanani) !> @todo chemistry error messages !> @todo Format this module according to PALM coding standard (see e.g. module !> template under http://palm.muk.uni-hannover.de/mosaik/downloads/8 or !> D3_coding_standard.pdf under https://palm.muk.uni-hannover.de/trac/downloads/16) ! !------------------------------------------------------------------------------! MODULE chemistry_model_mod USE kinds, ONLY: wp, iwp USE indices, ONLY: nz, nzb,nzt,nysg,nyng,nxlg,nxrg, & nys,nyn,nx,nxl,nxr,ny,wall_flags_0 USE pegrid, ONLY: myid, threads_per_task USE bulk_cloud_model_mod, & ONLY: bulk_cloud_model USE control_parameters, ONLY: bc_lr_cyc, bc_ns_cyc, dt_3d, humidity, & initializing_actions, message_string, & omega, tsc, intermediate_timestep_count, & intermediate_timestep_count_max, & timestep_scheme, use_prescribed_profile_data, ws_scheme_sca USE arrays_3d, ONLY: exner, hyp, pt, q, ql, rdf_sc, tend, zu USE chem_gasphase_mod, ONLY: nspec, spc_names, nkppctrl, nmaxfixsteps, & t_steps, chem_gasphase_integrate, vl_dim, & nvar, nreact, atol, rtol, nphot, phot_names USE cpulog, ONLY: cpu_log, log_point USE chem_modules USE statistics IMPLICIT NONE PRIVATE SAVE LOGICAL :: nest_chemistry = .TRUE. !< flag for nesting mode of chemical species, independent on parent or not ! !- Define chemical variables TYPE species_def CHARACTER(LEN=8) :: name CHARACTER(LEN=16) :: unit REAL(kind=wp),POINTER,DIMENSION(:,:,:) :: conc REAL(kind=wp),POINTER,DIMENSION(:,:,:) :: conc_av REAL(kind=wp),POINTER,DIMENSION(:,:,:) :: conc_p REAL(kind=wp),POINTER,DIMENSION(:,:,:) :: tconc_m REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:) :: cssws_av REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:) :: flux_s_cs REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:) :: diss_s_cs REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:) :: flux_l_cs REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:) :: diss_l_cs REAL(kind=wp),ALLOCATABLE,DIMENSION(:) :: conc_pr_init END TYPE species_def TYPE photols_def CHARACTER(LEN=8) :: name CHARACTER(LEN=16) :: unit REAL(kind=wp),POINTER,DIMENSION(:,:,:) :: freq END TYPE photols_def PUBLIC species_def PUBLIC photols_def TYPE(species_def),ALLOCATABLE,DIMENSION(:),TARGET, PUBLIC :: chem_species TYPE(photols_def),ALLOCATABLE,DIMENSION(:),TARGET, PUBLIC :: phot_frequen REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:,:),TARGET :: spec_conc_1 REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:,:),TARGET :: spec_conc_2 REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:,:),TARGET :: spec_conc_3 REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:,:),TARGET :: spec_conc_av REAL(kind=wp),ALLOCATABLE,DIMENSION(:,:,:,:),TARGET :: freq_1 INTEGER,DIMENSION(nkppctrl) :: icntrl ! Fine tuning kpp REAL(kind=wp),DIMENSION(nkppctrl) :: rcntrl ! Fine tuning kpp LOGICAL :: decycle_chem_lr = .FALSE. LOGICAL :: decycle_chem_ns = .FALSE. CHARACTER (LEN=20), DIMENSION(4) :: decycle_method = & (/'dirichlet','dirichlet','dirichlet','dirichlet'/) !< Decycling method at horizontal boundaries, !< 1=left, 2=right, 3=south, 4=north !< dirichlet = initial size distribution and !< chemical composition set for the ghost and !< first three layers !< neumann = zero gradient REAL(kind=wp), PUBLIC :: cs_time_step = 0._wp CHARACTER(10), PUBLIC :: photolysis_scheme ! 'constant', ! 'simple' (Simple parameterisation from MCM, Saunders et al., 2003, Atmos. Chem. Phys., 3, 161-180 ! 'fastj' (Wild et al., 2000, J. Atmos. Chem., 37, 245-282) STILL NOT IMPLEMENTED PUBLIC nest_chemistry PUBLIC nspec PUBLIC nreact PUBLIC nvar PUBLIC spc_names PUBLIC spec_conc_2 !- Interface section INTERFACE chem_3d_data_averaging MODULE PROCEDURE chem_3d_data_averaging END INTERFACE chem_3d_data_averaging INTERFACE chem_boundary_conds MODULE PROCEDURE chem_boundary_conds MODULE PROCEDURE chem_boundary_conds_decycle END INTERFACE chem_boundary_conds INTERFACE chem_check_data_output MODULE PROCEDURE chem_check_data_output END INTERFACE chem_check_data_output INTERFACE chem_data_output_2d MODULE PROCEDURE chem_data_output_2d END INTERFACE chem_data_output_2d INTERFACE chem_data_output_3d MODULE PROCEDURE chem_data_output_3d END INTERFACE chem_data_output_3d INTERFACE chem_data_output_mask MODULE PROCEDURE chem_data_output_mask END INTERFACE chem_data_output_mask INTERFACE chem_check_data_output_pr MODULE PROCEDURE chem_check_data_output_pr END INTERFACE chem_check_data_output_pr INTERFACE chem_check_parameters MODULE PROCEDURE chem_check_parameters END INTERFACE chem_check_parameters INTERFACE chem_define_netcdf_grid MODULE PROCEDURE chem_define_netcdf_grid END INTERFACE chem_define_netcdf_grid INTERFACE chem_header MODULE PROCEDURE chem_header END INTERFACE chem_header INTERFACE chem_init MODULE PROCEDURE chem_init END INTERFACE chem_init INTERFACE chem_init_profiles MODULE PROCEDURE chem_init_profiles END INTERFACE chem_init_profiles INTERFACE chem_integrate MODULE PROCEDURE chem_integrate_ij END INTERFACE chem_integrate INTERFACE chem_parin MODULE PROCEDURE chem_parin END INTERFACE chem_parin INTERFACE chem_prognostic_equations MODULE PROCEDURE chem_prognostic_equations MODULE PROCEDURE chem_prognostic_equations_ij END INTERFACE chem_prognostic_equations INTERFACE chem_rrd_local MODULE PROCEDURE chem_rrd_local END INTERFACE chem_rrd_local INTERFACE chem_statistics MODULE PROCEDURE chem_statistics END INTERFACE chem_statistics INTERFACE chem_swap_timelevel MODULE PROCEDURE chem_swap_timelevel END INTERFACE chem_swap_timelevel INTERFACE chem_wrd_local MODULE PROCEDURE chem_wrd_local END INTERFACE chem_wrd_local PUBLIC chem_3d_data_averaging, chem_boundary_conds, chem_check_data_output, & chem_check_data_output_pr, chem_check_parameters, & chem_data_output_2d, chem_data_output_3d, chem_data_output_mask, & chem_define_netcdf_grid, chem_header, chem_init, & chem_init_profiles, chem_integrate, chem_parin, & chem_prognostic_equations, chem_rrd_local, & chem_statistics, chem_swap_timelevel, chem_wrd_local CONTAINS ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine for averaging 3D data of chemical species. Due to the fact that !> the averaged chem arrays are allocated in chem_init, no if-query concerning !> the allocation is required (in any mode). Attention: If you just specify an !> averaged output quantity in the _p3dr file during restarts the first output !> includes the time between the beginning of the restart run and the first !> output time (not necessarily the whole averaging_interval you have !> specified in your _p3d/_p3dr file ) !------------------------------------------------------------------------------! SUBROUTINE chem_3d_data_averaging ( mode, variable ) USE control_parameters USE indices USE kinds USE surface_mod, & ONLY: surf_def_h, surf_lsm_h, surf_usm_h IMPLICIT NONE CHARACTER (LEN=*) :: mode !< CHARACTER (LEN=*) :: variable !< LOGICAL :: match_def !< flag indicating natural-type surface LOGICAL :: match_lsm !< flag indicating natural-type surface LOGICAL :: match_usm !< flag indicating urban-type surface INTEGER(iwp) :: i !< grid index x direction INTEGER(iwp) :: j !< grid index y direction INTEGER(iwp) :: k !< grid index z direction INTEGER(iwp) :: m !< running index surface type INTEGER(iwp) :: lsp !< running index for chem spcs IF ( mode == 'allocate' ) THEN DO lsp = 1, nspec IF ( TRIM(variable(1:3)) == 'kc_' .AND. & TRIM(variable(4:)) == TRIM(chem_species(lsp)%name)) THEN chem_species(lsp)%conc_av = 0.0_wp ENDIF ENDDO ELSEIF ( mode == 'sum' ) THEN DO lsp = 1, nspec IF ( TRIM(variable(1:3)) == 'kc_' .AND. & TRIM(variable(4:)) == TRIM(chem_species(lsp)%name)) THEN DO i = nxlg, nxrg DO j = nysg, nyng DO k = nzb, nzt+1 chem_species(lsp)%conc_av(k,j,i) = chem_species(lsp)%conc_av(k,j,i) + & chem_species(lsp)%conc(k,j,i) ENDDO ENDDO ENDDO ELSEIF ( TRIM(variable(4:)) == TRIM('cssws*') ) THEN DO i = nxl, nxr DO j = nys, nyn match_def = surf_def_h(0)%start_index(j,i) <= & surf_def_h(0)%end_index(j,i) match_lsm = surf_lsm_h%start_index(j,i) <= & surf_lsm_h%end_index(j,i) match_usm = surf_usm_h%start_index(j,i) <= & surf_usm_h%end_index(j,i) IF ( match_def ) THEN m = surf_def_h(0)%end_index(j,i) chem_species(lsp)%cssws_av(j,i) = & chem_species(lsp)%cssws_av(j,i) + & surf_def_h(0)%cssws(lsp,m) ELSEIF ( match_lsm .AND. .NOT. match_usm ) THEN m = surf_lsm_h%end_index(j,i) chem_species(lsp)%cssws_av(j,i) = & chem_species(lsp)%cssws_av(j,i) + & surf_lsm_h%cssws(lsp,m) ELSEIF ( match_usm ) THEN m = surf_usm_h%end_index(j,i) chem_species(lsp)%cssws_av(j,i) = & chem_species(lsp)%cssws_av(j,i) + & surf_usm_h%cssws(lsp,m) ENDIF ENDDO ENDDO ENDIF ENDDO ELSEIF ( mode == 'average' ) THEN DO lsp = 1, nspec IF ( TRIM(variable(1:3)) == 'kc_' .AND. & TRIM(variable(4:)) == TRIM(chem_species(lsp)%name)) THEN DO i = nxlg, nxrg DO j = nysg, nyng DO k = nzb, nzt+1 chem_species(lsp)%conc_av(k,j,i) = chem_species(lsp)%conc_av(k,j,i) / REAL( average_count_3d, KIND=wp ) ENDDO ENDDO ENDDO ELSEIF (TRIM(variable(4:)) == TRIM('cssws*') ) THEN DO i = nxlg, nxrg DO j = nysg, nyng chem_species(lsp)%cssws_av(j,i) = chem_species(lsp)%cssws_av(j,i) / REAL( average_count_3d, KIND=wp ) ENDDO ENDDO CALL exchange_horiz_2d( chem_species(lsp)%cssws_av, nbgp ) ENDIF ENDDO ENDIF END SUBROUTINE chem_3d_data_averaging ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine to initialize and set all boundary conditions for chemical species !------------------------------------------------------------------------------! SUBROUTINE chem_boundary_conds( mode ) USE control_parameters, & ONLY: air_chemistry, bc_radiation_l, bc_radiation_n, bc_radiation_r, & bc_radiation_s USE indices, & ONLY: nxl, nxr, nxlg, nxrg, nyng, nysg, nzt USE arrays_3d, & ONLY: dzu USE surface_mod, & ONLY: bc_h CHARACTER (len=*), INTENT(IN) :: mode INTEGER(iwp) :: i !< grid index x direction. INTEGER(iwp) :: j !< grid index y direction. INTEGER(iwp) :: k !< grid index z direction. INTEGER(iwp) :: kb !< variable to set respective boundary value, depends on facing. INTEGER(iwp) :: l !< running index boundary type, for up- and downward-facing walls. INTEGER(iwp) :: m !< running index surface elements. INTEGER(iwp) :: lsp !< running index for chem spcs. INTEGER(iwp) :: lph !< running index for photolysis frequencies SELECT CASE ( TRIM( mode ) ) CASE ( 'init' ) IF ( bc_cs_b == 'dirichlet' ) THEN ibc_cs_b = 0 ELSEIF ( bc_cs_b == 'neumann' ) THEN ibc_cs_b = 1 ELSE message_string = 'unknown boundary condition: bc_cs_b ="' // TRIM( bc_cs_b ) // '"' CALL message( 'chem_boundary_conds', 'CM0429', 1, 2, 0, 6, 0 ) !< ENDIF ! !-- Set Integer flags and check for possible erroneous settings for top !-- boundary condition. IF ( bc_cs_t == 'dirichlet' ) THEN ibc_cs_t = 0 ELSEIF ( bc_cs_t == 'neumann' ) THEN ibc_cs_t = 1 ELSEIF ( bc_cs_t == 'initial_gradient' ) THEN ibc_cs_t = 2 ELSEIF ( bc_cs_t == 'nested' ) THEN ibc_cs_t = 3 ELSE message_string = 'unknown boundary condition: bc_c_t ="' // TRIM( bc_cs_t ) // '"' CALL message( 'check_parameters', 'CM0430', 1, 2, 0, 6, 0 ) ENDIF CASE ( 'set_bc_bottomtop' ) !-- Bottom boundary condtions for chemical species DO lsp = 1, nspec IF ( ibc_cs_b == 0 ) THEN DO l = 0, 1 !-- Set index kb: For upward-facing surfaces (l=0), kb=-1, i.e. !-- the chem_species(nspec)%conc_p value at the topography top (k-1) !-- is set; for downward-facing surfaces (l=1), kb=1, i.e. the !-- value at the topography bottom (k+1) is set. kb = MERGE( -1, 1, l == 0 ) !$OMP PARALLEL DO PRIVATE( i, j, k ) DO m = 1, bc_h(l)%ns i = bc_h(l)%i(m) j = bc_h(l)%j(m) k = bc_h(l)%k(m) chem_species(lsp)%conc_p(k+kb,j,i) = chem_species(lsp)%conc(k+kb,j,i) ENDDO ENDDO ELSEIF ( ibc_cs_b == 1 ) THEN !-- in boundary_conds there is som extra loop over m here for passive tracer DO l = 0, 1 kb = MERGE( -1, 1, l == 0 ) !$OMP PARALLEL DO PRIVATE( i, j, k ) DO m = 1, bc_h(l)%ns i = bc_h(l)%i(m) j = bc_h(l)%j(m) k = bc_h(l)%k(m) chem_species(lsp)%conc_p(k+kb,j,i) = chem_species(lsp)%conc_p(k,j,i) ENDDO ENDDO ENDIF ENDDO ! end lsp loop !-- Top boundary conditions for chemical species - Should this not be done for all species? IF ( ibc_cs_t == 0 ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(nzt+1,:,:) = chem_species(lsp)%conc(nzt+1,:,:) ENDDO ELSEIF ( ibc_cs_t == 1 ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(nzt+1,:,:) = chem_species(lsp)%conc_p(nzt,:,:) ENDDO ELSEIF ( ibc_cs_t == 2 ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(nzt+1,:,:) = chem_species(lsp)%conc_p(nzt,:,:) + bc_cs_t_val(lsp) * dzu(nzt+1) ENDDO ENDIF ! CASE ( 'set_bc_lateral' ) !-- Lateral boundary conditions for chem species at inflow boundary !-- are automatically set when chem_species concentration is !-- initialized. The initially set value at the inflow boundary is not !-- touched during time integration, hence, this boundary value remains !-- at a constant value, which is the concentration that flows into the !-- domain. !-- Lateral boundary conditions for chem species at outflow boundary IF ( bc_radiation_s ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(:,nys-1,:) = chem_species(lsp)%conc_p(:,nys,:) ENDDO ELSEIF ( bc_radiation_n ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(:,nyn+1,:) = chem_species(lsp)%conc_p(:,nyn,:) ENDDO ELSEIF ( bc_radiation_l ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(:,:,nxl-1) = chem_species(lsp)%conc_p(:,:,nxl) ENDDO ELSEIF ( bc_radiation_r ) THEN DO lsp = 1, nspec chem_species(lsp)%conc_p(:,:,nxr+1) = chem_species(lsp)%conc_p(:,:,nxr) ENDDO ENDIF END SELECT END SUBROUTINE chem_boundary_conds ! !------------------------------------------------------------------------------! ! Description: ! ------------ !> Boundary conditions for prognostic variables in chemistry: decycling in the !> x-direction !----------------------------------------------------------------------------- SUBROUTINE chem_boundary_conds_decycle (cs_3d, cs_pr_init ) USE pegrid, & ONLY: myid IMPLICIT NONE INTEGER(iwp) :: boundary !< INTEGER(iwp) :: ee !< INTEGER(iwp) :: copied !< INTEGER(iwp) :: i !< INTEGER(iwp) :: j !< INTEGER(iwp) :: k !< INTEGER(iwp) :: ss !< REAL(wp), DIMENSION(nzb:nzt+1) :: cs_pr_init REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng,nxlg:nxrg) :: cs_3d REAL(wp) :: flag !< flag to mask topography grid points flag = 0.0_wp !-- Left and right boundaries IF ( decycle_chem_lr .AND. bc_lr_cyc ) THEN DO boundary = 1, 2 IF ( decycle_method(boundary) == 'dirichlet' ) THEN ! !-- Initial profile is copied to ghost and first three layers ss = 1 ee = 0 IF ( boundary == 1 .AND. nxl == 0 ) THEN ss = nxlg ee = nxl+2 ELSEIF ( boundary == 2 .AND. nxr == nx ) THEN ss = nxr-2 ee = nxrg ENDIF DO i = ss, ee DO j = nysg, nyng DO k = nzb+1, nzt flag = MERGE( 1.0_wp, 0.0_wp, & BTEST( wall_flags_0(k,j,i), 0 ) ) cs_3d(k,j,i) = cs_pr_init(k) * flag ENDDO ENDDO ENDDO ELSEIF ( decycle_method(boundary) == 'neumann' ) THEN ! !-- The value at the boundary is copied to the ghost layers to simulate !-- an outlet with zero gradient ss = 1 ee = 0 IF ( boundary == 1 .AND. nxl == 0 ) THEN ss = nxlg ee = nxl-1 copied = nxl ELSEIF ( boundary == 2 .AND. nxr == nx ) THEN ss = nxr+1 ee = nxrg copied = nxr ENDIF DO i = ss, ee DO j = nysg, nyng DO k = nzb+1, nzt flag = MERGE( 1.0_wp, 0.0_wp, & BTEST( wall_flags_0(k,j,i), 0 ) ) cs_3d(k,j,i) = cs_3d(k,j,copied) * flag ENDDO ENDDO ENDDO ELSE WRITE(message_string,*) & 'unknown decycling method: decycle_method (', & boundary, ') ="' // TRIM( decycle_method(boundary) ) // '"' CALL message( 'chem_boundary_conds_decycle', 'CM0431', & 1, 2, 0, 6, 0 ) ENDIF ENDDO ENDIF !-- South and north boundaries IF ( decycle_chem_ns .AND. bc_ns_cyc ) THEN DO boundary = 3, 4 IF ( decycle_method(boundary) == 'dirichlet' ) THEN ! !-- Initial profile is copied to ghost and first three layers ss = 1 ee = 0 IF ( boundary == 3 .AND. nys == 0 ) THEN ss = nysg ee = nys+2 ELSEIF ( boundary == 4 .AND. nyn == ny ) THEN ss = nyn-2 ee = nyng ENDIF DO i = nxlg, nxrg DO j = ss, ee DO k = nzb+1, nzt flag = MERGE( 1.0_wp, 0.0_wp, & BTEST( wall_flags_0(k,j,i), 0 ) ) cs_3d(k,j,i) = cs_pr_init(k) * flag ENDDO ENDDO ENDDO ELSEIF ( decycle_method(boundary) == 'neumann' ) THEN ! !-- The value at the boundary is copied to the ghost layers to simulate !-- an outlet with zero gradient ss = 1 ee = 0 IF ( boundary == 3 .AND. nys == 0 ) THEN ss = nysg ee = nys-1 copied = nys ELSEIF ( boundary == 4 .AND. nyn == ny ) THEN ss = nyn+1 ee = nyng copied = nyn ENDIF DO i = nxlg, nxrg DO j = ss, ee DO k = nzb+1, nzt flag = MERGE( 1.0_wp, 0.0_wp, & BTEST( wall_flags_0(k,j,i), 0 ) ) cs_3d(k,j,i) = cs_3d(k,copied,i) * flag ENDDO ENDDO ENDDO ELSE WRITE(message_string,*) & 'unknown decycling method: decycle_method (', & boundary, ') ="' // TRIM( decycle_method(boundary) ) // '"' CALL message( 'chem_boundary_conds_decycle', 'CM0432', & 1, 2, 0, 6, 0 ) ENDIF ENDDO ENDIF END SUBROUTINE chem_boundary_conds_decycle ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine for checking data output for chemical species !------------------------------------------------------------------------------! SUBROUTINE chem_check_data_output( var, unit, i, ilen, k ) USE control_parameters, & ONLY: data_output, message_string IMPLICIT NONE CHARACTER (LEN=*) :: unit !< CHARACTER (LEN=*) :: var !< INTEGER(iwp) :: i, lsp INTEGER(iwp) :: ilen INTEGER(iwp) :: k CHARACTER(len=16) :: spec_name unit = 'illegal' spec_name = TRIM(var(4:)) !< var 1:3 is 'kc_' or 'em_'. IF ( TRIM(var(1:3)) == 'em_' ) THEN DO lsp=1,nspec IF (TRIM(spec_name) == TRIM(chem_species(lsp)%name)) THEN unit = 'mol m-2 s-1' ENDIF !-- It is possible to plant PM10 and PM25 into the gasphase chemistry code !-- as passive species (e.g. 'passive' in GASPHASE_PREPROC/mechanisms): !-- set unit to micrograms per m**3 for PM10 and PM25 (PM2.5) IF (spec_name(1:2) == 'PM') THEN unit = 'kg m-2 s-1' ENDIF ENDDO ELSE DO lsp=1,nspec IF (TRIM(spec_name) == TRIM(chem_species(lsp)%name)) THEN unit = 'ppm' ENDIF ! It is possible to plant PM10 and PM25 into the gasphase chemistry code ! as passive species (e.g. 'passive' in GASPHASE_PREPROC/mechanisms): ! set unit to micrograms per m**3 for PM10 and PM25 (PM2.5) IF (spec_name(1:2) == 'PM') THEN unit = 'kg m-3' ENDIF ENDDO DO lsp=1,nphot IF (TRIM(spec_name) == TRIM(phot_frequen(lsp)%name)) THEN unit = 'sec-1' ENDIF ENDDO ENDIF RETURN END SUBROUTINE chem_check_data_output ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine for checking data output of profiles for chemistry model !------------------------------------------------------------------------------! SUBROUTINE chem_check_data_output_pr( variable, var_count, unit, dopr_unit ) USE arrays_3d USE control_parameters, & ONLY: data_output_pr, message_string, air_chemistry USE indices USE profil_parameter USE statistics IMPLICIT NONE CHARACTER (LEN=*) :: unit !< CHARACTER (LEN=*) :: variable !< CHARACTER (LEN=*) :: dopr_unit CHARACTER(len=16) :: spec_name INTEGER(iwp) :: var_count, lsp !< spec_name = TRIM(variable(4:)) IF ( .NOT. air_chemistry ) THEN message_string = 'data_output_pr = ' // & TRIM( data_output_pr(var_count) ) // ' is not imp' // & 'lemented for air_chemistry = .FALSE.' CALL message( 'chem_check_parameters', 'CM0433', 1, 2, 0, 6, 0 ) ELSE DO lsp = 1, nspec IF (TRIM( spec_name ) == TRIM( chem_species(lsp)%name ) ) THEN cs_pr_count = cs_pr_count+1 cs_pr_index(cs_pr_count) = lsp dopr_index(var_count) = pr_palm+cs_pr_count dopr_unit = 'ppm' IF (spec_name(1:2) == 'PM') THEN dopr_unit = 'kg m-3' ENDIF hom(:,2, dopr_index(var_count),:) = SPREAD( zu, 2, statistic_regions+1 ) unit = dopr_unit ENDIF ENDDO ENDIF END SUBROUTINE chem_check_data_output_pr ! !------------------------------------------------------------------------------! ! Description: ! ------------ !> Check parameters routine for chemistry_model_mod !------------------------------------------------------------------------------! SUBROUTINE chem_check_parameters IMPLICIT NONE LOGICAL :: found INTEGER (iwp) :: lsp_usr !< running index for user defined chem spcs INTEGER (iwp) :: lsp !< running index for chem spcs. !!-- check for chemical reactions status IF ( chem_gasphase_on ) THEN message_string = 'Chemical reactions: ON' CALL message( 'chem_check_parameters', 'CM0421', 0, 0, 0, 6, 0 ) ELSEIF ( .not. (chem_gasphase_on) ) THEN message_string = 'Chemical reactions: OFF' CALL message( 'chem_check_parameters', 'CM0422', 0, 0, 0, 6, 0 ) ENDIF !-- check for chemistry time-step IF ( call_chem_at_all_substeps ) THEN message_string = 'Chemistry is calculated at all meteorology time-step' CALL message( 'chem_check_parameters', 'CM0423', 0, 0, 0, 6, 0 ) ELSEIF ( .not. (call_chem_at_all_substeps) ) THEN message_string = 'Sub-time-steps are skipped for chemistry time-steps' CALL message( 'chem_check_parameters', 'CM0424', 0, 0, 0, 6, 0 ) ENDIF !-- check for photolysis scheme IF ( (photolysis_scheme /= 'simple') .AND. (photolysis_scheme /= 'constant') ) THEN message_string = 'Incorrect photolysis scheme selected, please check spelling' CALL message( 'chem_check_parameters', 'CM0425', 1, 2, 0, 6, 0 ) ENDIF !-- check for decycling of chem species IF ( (.not. any(decycle_method == 'neumann') ) .AND. (.not. any(decycle_method == 'dirichlet') ) ) THEN message_string = 'Incorrect boundary conditions. Only neumann or ' & // 'dirichlet &available for decycling chemical species ' CALL message( 'chem_check_parameters', 'CM0426', 1, 2, 0, 6, 0 ) ENDIF !--------------------- !-- chem_check_parameters is called before the array chem_species is allocated! !-- temporary switch of this part of the check RETURN !--------------------- !-- check for initial chem species input lsp_usr = 1 lsp = 1 DO WHILE ( cs_name (lsp_usr) /= 'novalue') found = .FALSE. DO lsp = 1, nvar IF ( TRIM(cs_name (lsp_usr)) == TRIM(chem_species(lsp)%name) ) THEN found = .TRUE. EXIT ENDIF ENDDO IF ( .not. found ) THEN message_string = 'Incorrect input for initial surface vaue: ' // TRIM(cs_name(lsp_usr)) CALL message( 'chem_check_parameters', 'CM0427', 0, 1, 0, 6, 0 ) ENDIF lsp_usr = lsp_usr + 1 ENDDO !-- check for surface emission flux chem species lsp_usr = 1 lsp = 1 DO WHILE ( surface_csflux_name (lsp_usr) /= 'novalue') found = .FALSE. DO lsp = 1, nvar IF ( TRIM(surface_csflux_name (lsp_usr)) == TRIM(chem_species(lsp)%name) ) THEN found = .TRUE. EXIT ENDIF ENDDO IF ( .not. found ) THEN message_string = 'Incorrect input of chemical species for surface emission fluxes: ' & // TRIM(surface_csflux_name(lsp_usr)) CALL message( 'chem_check_parameters', 'CM0428', 0, 1, 0, 6, 0 ) ENDIF lsp_usr = lsp_usr + 1 ENDDO END SUBROUTINE chem_check_parameters ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining 2D output variables for chemical species !> @todo: Remove "mode" from argument list, not used. !------------------------------------------------------------------------------! SUBROUTINE chem_data_output_2d( av, variable, found, grid, mode, local_pf, & two_d, nzb_do, nzt_do, fill_value ) USE indices USE kinds USE pegrid, ONLY: myid, threads_per_task IMPLICIT NONE CHARACTER (LEN=*) :: grid !< CHARACTER (LEN=*) :: mode !< CHARACTER (LEN=*) :: variable !< INTEGER(iwp) :: av !< flag to control data output of instantaneous or time-averaged data INTEGER(iwp) :: nzb_do !< lower limit of the domain (usually nzb) INTEGER(iwp) :: nzt_do !< upper limit of the domain (usually nzt+1) LOGICAL :: found !< LOGICAL :: two_d !< flag parameter that indicates 2D variables (horizontal cross sections) REAL(wp) :: fill_value REAL(wp), DIMENSION(nxl:nxr,nys:nyn,nzb:nzt+1) :: local_pf !< !-- local variables. CHARACTER(len=16) :: spec_name INTEGER(iwp) :: lsp INTEGER(iwp) :: i !< grid index along x-direction INTEGER(iwp) :: j !< grid index along y-direction INTEGER(iwp) :: k !< grid index along z-direction INTEGER(iwp) :: m !< running index surface elements INTEGER(iwp) :: char_len !< length of a character string found = .TRUE. char_len = LEN_TRIM(variable) spec_name = TRIM( variable(4:char_len-3) ) DO lsp=1,nspec IF (TRIM(spec_name) == TRIM(chem_species(lsp)%name) .AND. & ( (variable(char_len-2:) == '_xy') .OR. & (variable(char_len-2:) == '_xz') .OR. & (variable(char_len-2:) == '_yz') ) ) THEN ! !-- todo: remove or replace by "CALL message" mechanism (kanani) ! IF(myid == 0) WRITE(6,*) 'Output of species ' // TRIM(variable) // & ! TRIM(chem_species(lsp)%name) IF (av == 0) THEN DO i = nxl, nxr DO j = nys, nyn DO k = nzb_do, nzt_do local_pf(i,j,k) = MERGE( & chem_species(lsp)%conc(k,j,i), & REAL( fill_value, KIND = wp ), & BTEST( wall_flags_0(k,j,i), 0 ) ) ENDDO ENDDO ENDDO ELSE DO i = nxl, nxr DO j = nys, nyn DO k = nzb_do, nzt_do local_pf(i,j,k) = MERGE( & chem_species(lsp)%conc(k,j,i), & REAL( fill_value, KIND = wp ), & BTEST( wall_flags_0(k,j,i), 0 ) ) ENDDO ENDDO ENDDO ENDIF grid = 'zu' ENDIF ENDDO RETURN END SUBROUTINE chem_data_output_2d ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining 3D output variables for chemical species !------------------------------------------------------------------------------! SUBROUTINE chem_data_output_3d( av, variable, found, local_pf, fill_value, nzb_do, nzt_do ) USE indices USE kinds USE surface_mod !USE chem_modules, ONLY: nvar IMPLICIT NONE CHARACTER (LEN=*) :: variable !< INTEGER(iwp) :: av !< INTEGER(iwp) :: nzb_do !< lower limit of the data output (usually 0) INTEGER(iwp) :: nzt_do !< vertical upper limit of the data output (usually nz_do3d) LOGICAL :: found !< REAL(wp) :: fill_value !< REAL(sp), DIMENSION(nxl:nxr,nys:nyn,nzb_do:nzt_do) :: local_pf !-- local variables CHARACTER(len=16) :: spec_name INTEGER(iwp) :: i, j, k INTEGER(iwp) :: m, l !< running indices for surfaces INTEGER(iwp) :: lsp !< running index for chem spcs found = .FALSE. IF ( .NOT. (variable(1:3) == 'kc_' .OR. variable(1:3) == 'em_' ) ) THEN RETURN ENDIF spec_name = TRIM(variable(4:)) IF ( variable(1:3) == 'em_' ) THEN local_pf = 0.0_wp DO lsp = 1, nvar !!! cssws - nvar species, chem_species - nspec species !!! IF ( TRIM(spec_name) == TRIM(chem_species(lsp)%name) ) THEN ! no average for now DO m = 1, surf_usm_h%ns local_pf(surf_usm_h%i(m),surf_usm_h%j(m),surf_usm_h%k(m)) = & local_pf(surf_usm_h%i(m),surf_usm_h%j(m),surf_usm_h%k(m)) + surf_usm_h%cssws(lsp,m) ENDDO DO m = 1, surf_lsm_h%ns local_pf(surf_lsm_h%i(m),surf_lsm_h%j(m),surf_lsm_h%k(m)) = & local_pf(surf_lsm_h%i(m),surf_lsm_h%j(m),surf_lsm_h%k(m)) + surf_lsm_h%cssws(lsp,m) ENDDO DO l = 0, 3 DO m = 1, surf_usm_v(l)%ns local_pf(surf_usm_v(l)%i(m),surf_usm_v(l)%j(m),surf_usm_v(l)%k(m)) = & local_pf(surf_usm_v(l)%i(m),surf_usm_v(l)%j(m),surf_usm_v(l)%k(m)) + surf_usm_v(l)%cssws(lsp,m) ENDDO DO m = 1, surf_lsm_v(l)%ns local_pf(surf_lsm_v(l)%i(m),surf_lsm_v(l)%j(m),surf_lsm_v(l)%k(m)) = & local_pf(surf_lsm_v(l)%i(m),surf_lsm_v(l)%j(m),surf_lsm_v(l)%k(m)) + surf_lsm_v(l)%cssws(lsp,m) ENDDO ENDDO found = .TRUE. ENDIF ENDDO ELSE DO lsp=1,nspec IF (TRIM(spec_name) == TRIM(chem_species(lsp)%name)) THEN ! !-- todo: remove or replace by "CALL message" mechanism (kanani) ! IF(myid == 0 .AND. chem_debug0 ) WRITE(6,*) 'Output of species ' // TRIM(variable) // & ! TRIM(chem_species(lsp)%name) IF (av == 0) THEN DO i = nxl, nxr DO j = nys, nyn DO k = nzb_do, nzt_do local_pf(i,j,k) = MERGE( & chem_species(lsp)%conc(k,j,i), & REAL( fill_value, KIND = wp ), & BTEST( wall_flags_0(k,j,i), 0 ) ) ENDDO ENDDO ENDDO ELSE DO i = nxl, nxr DO j = nys, nyn DO k = nzb_do, nzt_do local_pf(i,j,k) = MERGE( & chem_species(lsp)%conc_av(k,j,i),& REAL( fill_value, KIND = wp ), & BTEST( wall_flags_0(k,j,i), 0 ) ) ENDDO ENDDO ENDDO ENDIF found = .TRUE. ENDIF ENDDO ENDIF RETURN END SUBROUTINE chem_data_output_3d ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining mask output variables for chemical species !------------------------------------------------------------------------------! SUBROUTINE chem_data_output_mask( av, variable, found, local_pf ) USE control_parameters USE indices USE kinds USE pegrid, ONLY: myid, threads_per_task USE surface_mod, ONLY: get_topography_top_index_ji IMPLICIT NONE CHARACTER(LEN=5) :: grid !< flag to distinquish between staggered grids CHARACTER (LEN=*):: variable !< INTEGER(iwp) :: av !< flag to control data output of instantaneous or time-averaged data LOGICAL :: found !< REAL(wp), DIMENSION(mask_size_l(mid,1),mask_size_l(mid,2),mask_size_l(mid,3)) :: & local_pf !< !-- local variables. CHARACTER(len=16) :: spec_name INTEGER(iwp) :: lsp INTEGER(iwp) :: i !< grid index along x-direction INTEGER(iwp) :: j !< grid index along y-direction INTEGER(iwp) :: k !< grid index along z-direction INTEGER(iwp) :: topo_top_ind !< k index of highest horizontal surface found = .TRUE. grid = 's' spec_name = TRIM( variable(4:) ) !av == 0 DO lsp=1,nspec IF (TRIM(spec_name) == TRIM(chem_species(lsp)%name) ) THEN ! !-- todo: remove or replace by "CALL message" mechanism (kanani) ! IF(myid == 0 .AND. chem_debug0 ) WRITE(6,*) 'Output of species ' // TRIM(variable) // & ! TRIM(chem_species(lsp)%name) IF (av == 0) THEN IF ( .NOT. mask_surface(mid) ) THEN DO i = 1, mask_size_l(mid,1) DO j = 1, mask_size_l(mid,2) DO k = 1, mask_size(mid,3) local_pf(i,j,k) = chem_species(lsp)%conc( & mask_k(mid,k), & mask_j(mid,j), & mask_i(mid,i) ) ENDDO ENDDO ENDDO ELSE ! !-- Terrain-following masked output DO i = 1, mask_size_l(mid,1) DO j = 1, mask_size_l(mid,2) ! !-- Get k index of highest horizontal surface topo_top_ind = get_topography_top_index_ji( & mask_j(mid,j), & mask_i(mid,i), & grid ) ! !-- Save output array DO k = 1, mask_size_l(mid,3) local_pf(i,j,k) = chem_species(lsp)%conc( & MIN( topo_top_ind+mask_k(mid,k), & nzt+1 ), & mask_j(mid,j), & mask_i(mid,i) ) ENDDO ENDDO ENDDO ENDIF ELSE IF ( .NOT. mask_surface(mid) ) THEN DO i = 1, mask_size_l(mid,1) DO j = 1, mask_size_l(mid,2) DO k = 1, mask_size_l(mid,3) local_pf(i,j,k) = chem_species(lsp)%conc_av( & mask_k(mid,k), & mask_j(mid,j), & mask_i(mid,i) ) ENDDO ENDDO ENDDO ELSE ! !-- Terrain-following masked output DO i = 1, mask_size_l(mid,1) DO j = 1, mask_size_l(mid,2) ! !-- Get k index of highest horizontal surface topo_top_ind = get_topography_top_index_ji( & mask_j(mid,j), & mask_i(mid,i), & grid ) ! !-- Save output array DO k = 1, mask_size_l(mid,3) local_pf(i,j,k) = chem_species(lsp)%conc_av( & MIN( topo_top_ind+mask_k(mid,k), & nzt+1 ), & mask_j(mid,j), & mask_i(mid,i) ) ENDDO ENDDO ENDDO ENDIF ENDIF found = .FALSE. ENDIF ENDDO RETURN END SUBROUTINE chem_data_output_mask ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining appropriate grid for netcdf variables. !> It is called out from subroutine netcdf. !------------------------------------------------------------------------------! SUBROUTINE chem_define_netcdf_grid( var, found, grid_x, grid_y, grid_z ) IMPLICIT NONE CHARACTER (LEN=*), INTENT(IN) :: var !< LOGICAL, INTENT(OUT) :: found !< CHARACTER (LEN=*), INTENT(OUT) :: grid_x !< CHARACTER (LEN=*), INTENT(OUT) :: grid_y !< CHARACTER (LEN=*), INTENT(OUT) :: grid_z !< found = .TRUE. IF ( var(1:3) == 'kc_' .OR. var(1:3) == 'em_' ) THEN !< always the same grid for chemistry variables grid_x = 'x' grid_y = 'y' grid_z = 'zu' ELSE found = .FALSE. grid_x = 'none' grid_y = 'none' grid_z = 'none' ENDIF END SUBROUTINE chem_define_netcdf_grid ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining header output for chemistry model !------------------------------------------------------------------------------! SUBROUTINE chem_header ( io ) IMPLICIT NONE INTEGER(iwp), INTENT(IN) :: io !< Unit of the output file INTEGER(iwp) :: lsp !< running index for chem spcs INTEGER(iwp) :: cs_fixed CHARACTER (LEN=80) :: docsflux_chr CHARACTER (LEN=80) :: docsinit_chr ! !-- Write chemistry model header WRITE( io, 1 ) !-- Gasphase reaction status IF ( chem_gasphase_on ) THEN WRITE( io, 2 ) ELSE WRITE( io, 3 ) ENDIF ! Chemistry time-step WRITE ( io, 4 ) cs_time_step !-- Emission mode info IF ( mode_emis == "DEFAULT" ) THEN WRITE( io, 5 ) ELSEIF ( mode_emis == "PARAMETERIZED" ) THEN WRITE( io, 6 ) ELSEIF ( mode_emis == "PRE-PROCESSED" ) THEN WRITE( io, 7 ) ENDIF !-- Photolysis scheme info IF ( photolysis_scheme == "simple" ) THEN WRITE( io, 8 ) ELSEIF (photolysis_scheme == "conastant" ) THEN WRITE( io, 9 ) ENDIF !-- Emission flux info lsp = 1 docsflux_chr ='Chemical species for surface emission flux: ' DO WHILE ( surface_csflux_name(lsp) /= 'novalue' ) docsflux_chr = TRIM( docsflux_chr ) // ' ' // TRIM( surface_csflux_name(lsp) ) // ',' IF ( LEN_TRIM( docsflux_chr ) >= 75 ) THEN WRITE ( io, 10 ) docsflux_chr docsflux_chr = ' ' ENDIF lsp = lsp + 1 ENDDO IF ( docsflux_chr /= '' ) THEN WRITE ( io, 10 ) docsflux_chr ENDIF !-- initializatoin of Surface and profile chemical species lsp = 1 docsinit_chr ='Chemical species for initial surface and profile emissions: ' DO WHILE ( cs_name(lsp) /= 'novalue' ) docsinit_chr = TRIM( docsinit_chr ) // ' ' // TRIM( cs_name(lsp) ) // ',' IF ( LEN_TRIM( docsinit_chr ) >= 75 ) THEN WRITE ( io, 11 ) docsinit_chr docsinit_chr = ' ' ENDIF lsp = lsp + 1 ENDDO IF ( docsinit_chr /= '' ) THEN WRITE ( io, 11 ) docsinit_chr ENDIF !-- number of variable and fix chemical species and number of reactions cs_fixed = nspec - nvar WRITE ( io, * ) ' --> Chemical species, variable: ', nvar WRITE ( io, * ) ' --> Chemical species, fixed : ', cs_fixed WRITE ( io, * ) ' --> Total number of reactions : ', nreact 1 FORMAT (//' Chemistry model information:'/ & ' ----------------------------'/) 2 FORMAT (' --> Chemical reactions are turned on') 3 FORMAT (' --> Chemical reactions are turned off') 4 FORMAT (' --> Time-step for chemical species: ',F6.2, ' s') 5 FORMAT (' --> Emission mode = DEFAULT ') 6 FORMAT (' --> Emission mode = PARAMETERIZED ') 7 FORMAT (' --> Emission mode = PRE-PROCESSED ') 8 FORMAT (' --> Photolysis scheme used = simple ') 9 FORMAT (' --> Photolysis scheme used = constant ') 10 FORMAT (/' ',A) 11 FORMAT (/' ',A) ! ! END SUBROUTINE chem_header ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine initializating chemistry_model_mod !------------------------------------------------------------------------------! SUBROUTINE chem_init USE control_parameters, & ONLY: message_string, io_blocks, io_group, turbulent_inflow USE arrays_3d, & ONLY: mean_inflow_profiles USE pegrid IMPLICIT none !-- local variables INTEGER :: i,j !< running index for for horiz numerical grid points INTEGER :: lsp !< running index for chem spcs INTEGER :: lpr_lev !< running index for chem spcs profile level ! !-- NOPOINTER version not implemented yet ! #if defined( __nopointer ) ! message_string = 'The chemistry module only runs with POINTER version' ! CALL message( 'chemistry_model_mod', 'CM0001', 1, 2, 0, 6, 0 ) ! #endif ! !-- Allocate memory for chemical species ALLOCATE( chem_species(nspec) ) ALLOCATE( spec_conc_1 (nzb:nzt+1,nysg:nyng,nxlg:nxrg,nspec) ) ALLOCATE( spec_conc_2 (nzb:nzt+1,nysg:nyng,nxlg:nxrg,nspec) ) ALLOCATE( spec_conc_3 (nzb:nzt+1,nysg:nyng,nxlg:nxrg,nspec) ) ALLOCATE( spec_conc_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg,nspec) ) ALLOCATE( phot_frequen(nphot) ) ALLOCATE( freq_1(nzb:nzt+1,nysg:nyng,nxlg:nxrg,nphot) ) ALLOCATE( bc_cs_t_val(nspec) ) ! !-- Initialize arrays spec_conc_1 (:,:,:,:) = 0.0_wp spec_conc_2 (:,:,:,:) = 0.0_wp spec_conc_3 (:,:,:,:) = 0.0_wp spec_conc_av(:,:,:,:) = 0.0_wp DO lsp = 1, nspec chem_species(lsp)%name = spc_names(lsp) chem_species(lsp)%conc (nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_1 (:,:,:,lsp) chem_species(lsp)%conc_p (nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_2 (:,:,:,lsp) chem_species(lsp)%tconc_m(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_3 (:,:,:,lsp) chem_species(lsp)%conc_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_av(:,:,:,lsp) ALLOCATE (chem_species(lsp)%cssws_av(nysg:nyng,nxlg:nxrg)) chem_species(lsp)%cssws_av = 0.0_wp ! !-- The following block can be useful when emission module is not applied. & !-- if emission module is applied the following block will be overwritten. ALLOCATE (chem_species(lsp)%flux_s_cs(nzb+1:nzt,0:threads_per_task-1)) ALLOCATE (chem_species(lsp)%diss_s_cs(nzb+1:nzt,0:threads_per_task-1)) ALLOCATE (chem_species(lsp)%flux_l_cs(nzb+1:nzt,nys:nyn,0:threads_per_task-1)) ALLOCATE (chem_species(lsp)%diss_l_cs(nzb+1:nzt,nys:nyn,0:threads_per_task-1)) chem_species(lsp)%flux_s_cs = 0.0_wp chem_species(lsp)%flux_l_cs = 0.0_wp chem_species(lsp)%diss_s_cs = 0.0_wp chem_species(lsp)%diss_l_cs = 0.0_wp ! !-- Allocate memory for initial concentration profiles !-- (concentration values come from namelist) !-- (@todo (FK): Because of this, chem_init is called in palm before !-- check_parameters, since conc_pr_init is used there. !-- We have to find another solution since chem_init should !-- eventually be called from init_3d_model!!) ALLOCATE ( chem_species(lsp)%conc_pr_init(0:nz+1) ) chem_species(lsp)%conc_pr_init(:) = 0.0_wp ENDDO ! !-- Initial concentration of profiles is prescribed by parameters cs_profile !-- and cs_heights in the namelist &chemistry_parameters CALL chem_init_profiles ! !-- Initialize model variables IF ( TRIM( initializing_actions ) /= 'read_restart_data' .AND. & TRIM( initializing_actions ) /= 'cyclic_fill' ) THEN !-- First model run of a possible job queue. !-- Initial profiles of the variables must be computed. IF ( INDEX( initializing_actions, 'set_1d-model_profiles' ) /= 0 ) THEN CALL location_message( 'initializing with 1D chemistry model profiles', .FALSE. ) ! !-- Transfer initial profiles to the arrays of the 3D model DO lsp = 1, nspec DO i = nxlg, nxrg DO j = nysg, nyng DO lpr_lev = 1, nz + 1 chem_species(lsp)%conc(lpr_lev,j,i) = chem_species(lsp)%conc_pr_init(lpr_lev) ENDDO ENDDO ENDDO ENDDO ELSEIF ( INDEX(initializing_actions, 'set_constant_profiles') /= 0 ) & THEN CALL location_message( 'initializing with constant chemistry profiles', .FALSE. ) DO lsp = 1, nspec DO i = nxlg, nxrg DO j = nysg, nyng chem_species(lsp)%conc(:,j,i) = chem_species(lsp)%conc_pr_init ENDDO ENDDO ENDDO ENDIF ! !-- If required, change the surface chem spcs at the start of the 3D run IF ( cs_surface_initial_change(1) /= 0.0_wp ) THEN DO lsp = 1, nspec chem_species(lsp)%conc(nzb,:,:) = chem_species(lsp)%conc(nzb,:,:) + & cs_surface_initial_change(lsp) ENDDO ENDIF ! !-- Initiale old and new time levels. DO lsp = 1, nvar chem_species(lsp)%tconc_m = 0.0_wp chem_species(lsp)%conc_p = chem_species(lsp)%conc ENDDO ENDIF !--- new code add above this line DO lsp = 1, nphot phot_frequen(lsp)%name = phot_names(lsp) ! !-- todo: remove or replace by "CALL message" mechanism (kanani) ! IF( myid == 0 ) THEN ! WRITE(6,'(a,i4,3x,a)') 'Photolysis: ',lsp,trim(phot_names(lsp)) ! ENDIF phot_frequen(lsp)%freq(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => freq_1(:,:,:,lsp) ENDDO RETURN END SUBROUTINE chem_init ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining initial vertical profiles of chemical species (given by !> namelist parameters chem_profiles and chem_heights) --> which should work !> analogue to parameters u_profile, v_profile and uv_heights) !------------------------------------------------------------------------------! SUBROUTINE chem_init_profiles !< SUBROUTINE is called from chem_init in case of !< TRIM( initializing_actions ) /= 'read_restart_data' !< We still need to see what has to be done in case of restart run USE chem_modules IMPLICIT NONE !-- Local variables INTEGER :: lsp !< running index for number of species in derived data type species_def INTEGER :: lsp_usr !< running index for number of species (user defined) in cs_names, cs_profiles etc INTEGER :: lpr_lev !< running index for profile level for each chem spcs. INTEGER :: npr_lev !< the next available profile lev !----------------- !-- Parameter "cs_profile" and "cs_heights" are used to prescribe user defined initial profiles !-- and heights. If parameter "cs_profile" is not prescribed then initial surface values !-- "cs_surface" are used as constant initial profiles for each species. If "cs_profile" and !-- "cs_heights" are prescribed, their values will!override the constant profile given by !-- "cs_surface". ! IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN lsp_usr = 1 DO WHILE ( TRIM( cs_name( lsp_usr ) ) /= 'novalue' ) !'novalue' is the default DO lsp = 1, nspec ! !-- create initial profile (conc_pr_init) for each chemical species IF ( TRIM( chem_species(lsp)%name ) == TRIM( cs_name(lsp_usr) ) ) THEN ! IF ( cs_profile(lsp_usr,1) == 9999999.9_wp ) THEN !-- set a vertically constant profile based on the surface conc (cs_surface(lsp_usr)) of each species DO lpr_lev = 0, nzt+1 chem_species(lsp)%conc_pr_init(lpr_lev) = cs_surface(lsp_usr) ENDDO ELSE IF ( cs_heights(1,1) /= 0.0_wp ) THEN message_string = 'The surface value of cs_heights must be 0.0' CALL message( 'chem_check_parameters', 'CM0434', 1, 2, 0, 6, 0 ) ENDIF use_prescribed_profile_data = .TRUE. npr_lev = 1 ! chem_species(lsp)%conc_pr_init(0) = 0.0_wp DO lpr_lev = 1, nz+1 IF ( npr_lev < 100 ) THEN DO WHILE ( cs_heights(lsp_usr, npr_lev+1) <= zu(lpr_lev) ) npr_lev = npr_lev + 1 IF ( npr_lev == 100 ) THEN message_string = 'number of chem spcs exceeding the limit' CALL message( 'chem_check_parameters', 'CM0435', 1, 2, 0, 6, 0 ) EXIT ENDIF ENDDO ENDIF IF ( npr_lev < 100 .AND. cs_heights(lsp_usr, npr_lev + 1) /= 9999999.9_wp ) THEN chem_species(lsp)%conc_pr_init(lpr_lev) = cs_profile(lsp_usr, npr_lev) + & ( zu(lpr_lev) - cs_heights(lsp_usr, npr_lev) ) / & ( cs_heights(lsp_usr, (npr_lev + 1)) - cs_heights(lsp_usr, npr_lev ) ) * & ( cs_profile(lsp_usr, (npr_lev + 1)) - cs_profile(lsp_usr, npr_lev ) ) ELSE chem_species(lsp)%conc_pr_init(lpr_lev) = cs_profile(lsp_usr, npr_lev) ENDIF ENDDO ENDIF !-- If a profile is prescribed explicity using cs_profiles and cs_heights, then !-- chem_species(lsp)%conc_pr_init is populated with the specific "lsp" based !-- on the cs_profiles(lsp_usr,:) and cs_heights(lsp_usr,:). ENDIF ENDDO lsp_usr = lsp_usr + 1 ENDDO ENDIF END SUBROUTINE chem_init_profiles ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine to integrate chemical species in the given chemical mechanism !------------------------------------------------------------------------------! SUBROUTINE chem_integrate_ij (i, j) USE cpulog, & ONLY: cpu_log, log_point USE statistics, & ONLY: weight_pres USE control_parameters, & ONLY: dt_3d, intermediate_timestep_count,simulated_time IMPLICIT none INTEGER,INTENT(IN) :: i,j !-- local variables INTEGER(iwp) :: lsp !< running index for chem spcs. INTEGER(iwp) :: lph !< running index for photolysis frequencies INTEGER :: k,m,istatf INTEGER,DIMENSION(20) :: istatus REAL(kind=wp),DIMENSION(nzb+1:nzt,nspec) :: tmp_conc REAL(kind=wp),DIMENSION(nzb+1:nzt) :: tmp_temp REAL(kind=wp),DIMENSION(nzb+1:nzt) :: tmp_qvap REAL(kind=wp),DIMENSION(nzb+1:nzt,nphot) :: tmp_phot REAL(kind=wp),DIMENSION(nzb+1:nzt) :: tmp_fact REAL(kind=wp),DIMENSION(nzb+1:nzt) :: tmp_fact_i !< conversion factor between !< molecules cm^{-3} and ppm INTEGER,DIMENSION(nzb+1:nzt) :: nacc !< Number of accepted steps INTEGER,DIMENSION(nzb+1:nzt) :: nrej !< Number of rejected steps REAL(wp) :: conv !< conversion factor REAL(wp), PARAMETER :: ppm2fr = 1.0e-6_wp !< Conversion factor ppm to fraction REAL(wp), PARAMETER :: xm_air = 28.96_wp !< Mole mass of dry air REAL(wp), PARAMETER :: xm_h2o = 18.01528_wp !< Mole mass of water vapor REAL(wp), PARAMETER :: pref_i = 1._wp / 100000.0_wp !< inverse reference pressure (1/Pa) REAL(wp), PARAMETER :: t_std = 273.15_wp !< standard pressure (Pa) REAL(wp), PARAMETER :: p_std = 101325.0_wp !< standard pressure (Pa) REAL(wp), PARAMETER :: vmolcm = 22.414e3_wp !< Mole volume (22.414 l) in cm^{-3} REAL(wp), PARAMETER :: xna = 6.022e23_wp !< Avogadro number (molecules/mol) REAL(wp),DIMENSION(size(rcntrl)) :: rcntrl_local REAL(kind=wp) :: dt_chem CALL cpu_log( log_point(80), '[chem_integrate_ij]', 'start' ) !< set chem_gasphase_on to .FALSE. if you want to skip computation of gas phase chemistry IF (chem_gasphase_on) THEN nacc = 0 nrej = 0 tmp_temp(:) = pt(nzb+1:nzt,j,i) * exner(nzb+1:nzt) ! ppm to molecules/cm**3 ! tmp_fact = 1.e-6_wp*6.022e23_wp/(22.414_wp*1000._wp) * 273.15_wp * hyp(nzb+1:nzt)/( 101300.0_wp * tmp_temp ) conv = ppm2fr * xna / vmolcm tmp_fact(:) = conv * t_std * hyp(nzb+1:nzt) / (tmp_temp(:) * p_std) tmp_fact_i = 1.0_wp/tmp_fact IF ( humidity ) THEN IF ( bulk_cloud_model ) THEN tmp_qvap(:) = ( q(nzb+1:nzt,j,i) - ql(nzb+1:nzt,j,i) ) * xm_air/xm_h2o * tmp_fact(:) ELSE tmp_qvap(:) = q(nzb+1:nzt,j,i) * xm_air/xm_h2o * tmp_fact(:) ENDIF ELSE tmp_qvap(:) = 0.01 * tmp_fact(:) !< Constant value for q if water vapor is not computed ENDIF DO lsp = 1,nspec tmp_conc(:,lsp) = chem_species(lsp)%conc(nzb+1:nzt,j,i) * tmp_fact(:) ENDDO DO lph = 1,nphot tmp_phot(:,lph) = phot_frequen(lph)%freq(nzb+1:nzt,j,i) ENDDO ! !-- todo: remove (kanani) ! IF(myid == 0 .AND. chem_debug0 ) THEN ! IF (i == 10 .and. j == 10) WRITE(0,*) 'begin chemics step ',dt_3d ! ENDIF !-- Compute length of time step IF ( call_chem_at_all_substeps ) THEN dt_chem = dt_3d * weight_pres(intermediate_timestep_count) ELSE dt_chem = dt_3d ENDIF cs_time_step = dt_chem CALL cpu_log( log_point(81), '{chem_gasphase_integrate}', 'start' ) IF(maxval(rcntrl) > 0.0) THEN ! Only if rcntrl is set IF( simulated_time <= 2*dt_3d) THEN rcntrl_local = 0 ! !-- todo: remove (kanani) ! WRITE(9,'(a,2f10.3)') 'USE Default rcntrl in the first steps ',simulated_time,dt_3d ELSE rcntrl_local = rcntrl ENDIF ELSE rcntrl_local = 0 END IF CALL chem_gasphase_integrate (dt_chem, tmp_conc, tmp_temp, tmp_qvap, tmp_fact, tmp_phot, & icntrl_i = icntrl, rcntrl_i = rcntrl_local, xnacc = nacc, xnrej = nrej, istatus=istatus) CALL cpu_log( log_point(81), '{chem_gasphase_integrate}', 'stop' ) DO lsp = 1,nspec chem_species(lsp)%conc (nzb+1:nzt,j,i) = tmp_conc(:,lsp) * tmp_fact_i(:) ENDDO ENDIF CALL cpu_log( log_point(80), '[chem_integrate_ij]', 'stop' ) RETURN END SUBROUTINE chem_integrate_ij ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine defining parin for &chemistry_parameters for chemistry model !------------------------------------------------------------------------------! SUBROUTINE chem_parin USE chem_modules USE control_parameters USE kinds USE pegrid USE statistics IMPLICIT NONE CHARACTER (LEN=80) :: line !< dummy string that contains the current line of the parameter file CHARACTER (LEN=3) :: cs_prefix REAL(wp), DIMENSION(nmaxfixsteps) :: my_steps !< List of fixed timesteps my_step(1) = 0.0 automatic stepping INTEGER(iwp) :: i !< INTEGER(iwp) :: j !< INTEGER(iwp) :: max_pr_cs_tmp !< NAMELIST /chemistry_parameters/ bc_cs_b, & bc_cs_t, & call_chem_at_all_substeps, & chem_debug0, & chem_debug1, & chem_debug2, & chem_gasphase_on, & cs_heights, & cs_name, & cs_profile, & cs_profile_name, & cs_surface, & decycle_chem_lr, & decycle_chem_ns, & decycle_method, & emiss_factor_main, & emiss_factor_side, & icntrl, & main_street_id, & max_street_id, & my_steps, & nest_chemistry, & rcntrl, & side_street_id, & photolysis_scheme, & wall_csflux, & cs_vertical_gradient, & top_csflux, & surface_csflux, & surface_csflux_name, & cs_surface_initial_change, & cs_vertical_gradient_level, & ! namelist parameters for emissions mode_emis, & time_fac_type, & daytype_mdh, & do_emis !-- analogue to chem_names(nspj) we could invent chem_surfaceflux(nspj) and chem_topflux(nspj) !-- so this way we could prescribe a specific flux value for each species !> chemistry_parameters for initial profiles !> cs_names = 'O3', 'NO2', 'NO', ... to set initial profiles) !> cs_heights(1,:) = 0.0, 100.0, 500.0, 2000.0, .... (height levels where concs will be prescribed for O3) !> cs_heights(2,:) = 0.0, 200.0, 400.0, 1000.0, .... (same for NO2 etc.) !> cs_profiles(1,:) = 10.0, 20.0, 20.0, 30.0, ..... (chem spcs conc at height lvls chem_heights(1,:)) etc. !> If the respective concentration profile should be constant with height, then use "cs_surface( number of spcs)" !> then write these cs_surface values to chem_species(lsp)%conc_pr_init(:) ! !-- Read chem namelist INTEGER :: ier CHARACTER(LEN=64) :: text CHARACTER(LEN=8) :: solver_type icntrl = 0 rcntrl = 0.0_wp my_steps = 0.0_wp photolysis_scheme = 'simple' atol = 1.0_wp rtol = 0.01_wp ! !-- Try to find chemistry package REWIND ( 11 ) line = ' ' DO WHILE ( INDEX( line, '&chemistry_parameters' ) == 0 ) READ ( 11, '(A)', END=20 ) line ENDDO BACKSPACE ( 11 ) ! !-- Read chemistry namelist READ ( 11, chemistry_parameters, ERR = 10, END = 20 ) ! !-- Enable chemistry model air_chemistry = .TRUE. GOTO 20 10 BACKSPACE( 11 ) READ( 11 , '(A)') line CALL parin_fail_message( 'chemistry_parameters', line ) 20 CONTINUE ! !-- check for emission mode for chem species IF ( (mode_emis /= 'PARAMETERIZED') .AND. ( mode_emis /= 'DEFAULT') .AND. (mode_emis /= 'PRE-PROCESSED' ) ) THEN message_string = 'Incorrect mode_emiss option select. Please check spelling' CALL message( 'chem_check_parameters', 'CM0436', 1, 2, 0, 6, 0 ) ENDIF t_steps = my_steps !-- Determine the number of user-defined profiles and append them to the !-- standard data output (data_output_pr) max_pr_cs_tmp = 0 i = 1 DO WHILE ( data_output_pr(i) /= ' ' .AND. i <= 100 ) IF ( TRIM( data_output_pr(i)(1:3)) == 'kc_' ) THEN max_pr_cs_tmp = max_pr_cs_tmp+1 ENDIF i = i +1 ENDDO IF ( max_pr_cs_tmp > 0 ) THEN cs_pr_namelist_found = .TRUE. max_pr_cs = max_pr_cs_tmp ENDIF ! Set Solver Type IF(icntrl(3) == 0) THEN solver_type = 'rodas3' !Default ELSE IF(icntrl(3) == 1) THEN solver_type = 'ros2' ELSE IF(icntrl(3) == 2) THEN solver_type = 'ros3' ELSE IF(icntrl(3) == 3) THEN solver_type = 'ro4' ELSE IF(icntrl(3) == 4) THEN solver_type = 'rodas3' ELSE IF(icntrl(3) == 5) THEN solver_type = 'rodas4' ELSE IF(icntrl(3) == 6) THEN solver_type = 'Rang3' ELSE message_string = 'illegal solver type' CALL message( 'chem_parin', 'PA0506', 1, 2, 0, 6, 0 ) END IF ! !-- todo: remove or replace by "CALL message" mechanism (kanani) ! write(text,*) 'gas_phase chemistry: solver_type = ',trim(solver_type) !kk Has to be changed to right calling sequence !kk CALL location_message( trim(text), .FALSE. ) ! IF(myid == 0) THEN ! write(9,*) ' ' ! write(9,*) 'kpp setup ' ! write(9,*) ' ' ! write(9,*) ' gas_phase chemistry: solver_type = ',trim(solver_type) ! write(9,*) ' ' ! write(9,*) ' Hstart = ',rcntrl(3) ! write(9,*) ' FacMin = ',rcntrl(4) ! write(9,*) ' FacMax = ',rcntrl(5) ! write(9,*) ' ' ! IF(vl_dim > 1) THEN ! write(9,*) ' Vector mode vektor length = ',vl_dim ! ELSE ! write(9,*) ' Scalar mode' ! ENDIF ! write(9,*) ' ' ! END IF RETURN END SUBROUTINE chem_parin ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine calculating prognostic equations for chemical species !> (vector-optimized). !> Routine is called separately for each chemical species over a loop from !> prognostic_equations. !------------------------------------------------------------------------------! SUBROUTINE chem_prognostic_equations ( cs_scalar_p, cs_scalar, tcs_scalar_m, & pr_init_cs, ilsp ) USE advec_s_pw_mod, & ONLY: advec_s_pw USE advec_s_up_mod, & ONLY: advec_s_up USE advec_ws, & ONLY: advec_s_ws USE diffusion_s_mod, & ONLY: diffusion_s USE indices, & ONLY: nxl, nxr, nyn, nys, wall_flags_0 USE pegrid USE surface_mod, & ONLY: surf_def_h, surf_def_v, surf_lsm_h, surf_lsm_v, surf_usm_h, & surf_usm_v IMPLICIT NONE INTEGER :: i !< running index INTEGER :: j !< running index INTEGER :: k !< running index INTEGER(iwp),INTENT(IN) :: ilsp !< REAL(wp), DIMENSION(0:nz+1) :: pr_init_cs !< REAL(wp), DIMENSION(:,:,:), POINTER :: cs_scalar !< REAL(wp), DIMENSION(:,:,:), POINTER :: cs_scalar_p !< REAL(wp), DIMENSION(:,:,:), POINTER :: tcs_scalar_m !< ! !-- Tendency terms for chemical species tend = 0.0_wp ! !-- Advection terms IF ( timestep_scheme(1:5) == 'runge' ) THEN IF ( ws_scheme_sca ) THEN CALL advec_s_ws( cs_scalar, 'kc' ) ELSE CALL advec_s_pw( cs_scalar ) ENDIF ELSE CALL advec_s_up( cs_scalar ) ENDIF ! !-- Diffusion terms (the last three arguments are zero) CALL diffusion_s( cs_scalar, & surf_def_h(0)%cssws(ilsp,:), & surf_def_h(1)%cssws(ilsp,:), & surf_def_h(2)%cssws(ilsp,:), & surf_lsm_h%cssws(ilsp,:), & surf_usm_h%cssws(ilsp,:), & surf_def_v(0)%cssws(ilsp,:), & surf_def_v(1)%cssws(ilsp,:), & surf_def_v(2)%cssws(ilsp,:), & surf_def_v(3)%cssws(ilsp,:), & surf_lsm_v(0)%cssws(ilsp,:), & surf_lsm_v(1)%cssws(ilsp,:), & surf_lsm_v(2)%cssws(ilsp,:), & surf_lsm_v(3)%cssws(ilsp,:), & surf_usm_v(0)%cssws(ilsp,:), & surf_usm_v(1)%cssws(ilsp,:), & surf_usm_v(2)%cssws(ilsp,:), & surf_usm_v(3)%cssws(ilsp,:) ) ! !-- Prognostic equation for chemical species DO i = nxl, nxr DO j = nys, nyn DO k = nzb+1, nzt cs_scalar_p(k,j,i) = cs_scalar(k,j,i) & + ( dt_3d * & ( tsc(2) * tend(k,j,i) & + tsc(3) * tcs_scalar_m(k,j,i) & ) & - tsc(5) * rdf_sc(k) & * ( cs_scalar(k,j,i) - pr_init_cs(k) ) & ) & * MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_0(k,j,i), 0 ) ) IF ( cs_scalar_p(k,j,i) < 0.0_wp ) cs_scalar_p(k,j,i) = 0.1_wp * cs_scalar(k,j,i) ENDDO ENDDO ENDDO ! !-- Calculate tendencies for the next Runge-Kutta step IF ( timestep_scheme(1:5) == 'runge' ) THEN IF ( intermediate_timestep_count == 1 ) THEN DO i = nxl, nxr DO j = nys, nyn DO k = nzb+1, nzt tcs_scalar_m(k,j,i) = tend(k,j,i) ENDDO ENDDO ENDDO ELSEIF ( intermediate_timestep_count < & intermediate_timestep_count_max ) THEN DO i = nxl, nxr DO j = nys, nyn DO k = nzb+1, nzt tcs_scalar_m(k,j,i) = - 9.5625_wp * tend(k,j,i) & + 5.3125_wp * tcs_scalar_m(k,j,i) ENDDO ENDDO ENDDO ENDIF ENDIF END SUBROUTINE chem_prognostic_equations !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine calculating prognostic equations for chemical species !> (cache-optimized). !> Routine is called separately for each chemical species over a loop from !> prognostic_equations. !------------------------------------------------------------------------------! SUBROUTINE chem_prognostic_equations_ij ( cs_scalar_p, cs_scalar, tcs_scalar_m, pr_init_cs, & i, j, i_omp_start, tn, ilsp, flux_s_cs, diss_s_cs, & flux_l_cs, diss_l_cs ) USE pegrid USE advec_ws, ONLY: advec_s_ws USE advec_s_pw_mod, ONLY: advec_s_pw USE advec_s_up_mod, ONLY: advec_s_up USE diffusion_s_mod, ONLY: diffusion_s USE indices, ONLY: wall_flags_0 USE surface_mod, ONLY: surf_def_h, surf_def_v, surf_lsm_h, surf_lsm_v, surf_usm_h, & surf_usm_v IMPLICIT NONE REAL(wp), DIMENSION(:,:,:), POINTER :: cs_scalar_p, cs_scalar, tcs_scalar_m INTEGER(iwp),INTENT(IN) :: i, j, i_omp_start, tn, ilsp REAL(wp), DIMENSION(nzb+1:nzt,0:threads_per_task-1) :: flux_s_cs !< REAL(wp), DIMENSION(nzb+1:nzt,0:threads_per_task-1) :: diss_s_cs !< REAL(wp), DIMENSION(nzb+1:nzt,nys:nyn,0:threads_per_task-1) :: flux_l_cs !< REAL(wp), DIMENSION(nzb+1:nzt,nys:nyn,0:threads_per_task-1) :: diss_l_cs !< REAL(wp), DIMENSION(0:nz+1) :: pr_init_cs !< !-- local variables INTEGER :: k ! !-- Tendency-terms for chem spcs. tend(:,j,i) = 0.0_wp ! !-- Advection terms IF ( timestep_scheme(1:5) == 'runge' ) THEN IF ( ws_scheme_sca ) THEN CALL advec_s_ws( i, j, cs_scalar, 'kc', flux_s_cs, diss_s_cs, & flux_l_cs, diss_l_cs, i_omp_start, tn ) ELSE CALL advec_s_pw( i, j, cs_scalar ) ENDIF ELSE CALL advec_s_up( i, j, cs_scalar ) ENDIF ! !-- Diffusion terms (the last three arguments are zero) CALL diffusion_s( i, j, cs_scalar, & surf_def_h(0)%cssws(ilsp,:), surf_def_h(1)%cssws(ilsp,:), & surf_def_h(2)%cssws(ilsp,:), & surf_lsm_h%cssws(ilsp,:), surf_usm_h%cssws(ilsp,:), & surf_def_v(0)%cssws(ilsp,:), surf_def_v(1)%cssws(ilsp,:), & surf_def_v(2)%cssws(ilsp,:), surf_def_v(3)%cssws(ilsp,:), & surf_lsm_v(0)%cssws(ilsp,:), surf_lsm_v(1)%cssws(ilsp,:), & surf_lsm_v(2)%cssws(ilsp,:), surf_lsm_v(3)%cssws(ilsp,:), & surf_usm_v(0)%cssws(ilsp,:), surf_usm_v(1)%cssws(ilsp,:), & surf_usm_v(2)%cssws(ilsp,:), surf_usm_v(3)%cssws(ilsp,:) ) ! !-- Prognostic equation for chem spcs DO k = nzb+1, nzt cs_scalar_p(k,j,i) = cs_scalar(k,j,i) + ( dt_3d * & ( tsc(2) * tend(k,j,i) + & tsc(3) * tcs_scalar_m(k,j,i) ) & - tsc(5) * rdf_sc(k) & * ( cs_scalar(k,j,i) - pr_init_cs(k) ) & ) & * MERGE( 1.0_wp, 0.0_wp, & BTEST( wall_flags_0(k,j,i), 0 ) & ) IF ( cs_scalar_p(k,j,i) < 0.0_wp ) cs_scalar_p(k,j,i) = 0.1_wp * cs_scalar(k,j,i) !FKS6 ENDDO ! !-- Calculate tendencies for the next Runge-Kutta step IF ( timestep_scheme(1:5) == 'runge' ) THEN IF ( intermediate_timestep_count == 1 ) THEN DO k = nzb+1, nzt tcs_scalar_m(k,j,i) = tend(k,j,i) ENDDO ELSEIF ( intermediate_timestep_count < & intermediate_timestep_count_max ) THEN DO k = nzb+1, nzt tcs_scalar_m(k,j,i) = -9.5625_wp * tend(k,j,i) + & 5.3125_wp * tcs_scalar_m(k,j,i) ENDDO ENDIF ENDIF END SUBROUTINE chem_prognostic_equations_ij ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine to read restart data of chemical species !------------------------------------------------------------------------------! SUBROUTINE chem_rrd_local( i, k, nxlf, nxlc, nxl_on_file, nxrf, nxrc, & nxr_on_file, nynf, nync, nyn_on_file, nysf, nysc, & nys_on_file, tmp_3d, found ) USE control_parameters USE indices USE pegrid IMPLICIT NONE CHARACTER (LEN=20) :: spc_name_av !< INTEGER(iwp) :: i, lsp !< INTEGER(iwp) :: k !< INTEGER(iwp) :: nxlc !< INTEGER(iwp) :: nxlf !< INTEGER(iwp) :: nxl_on_file !< INTEGER(iwp) :: nxrc !< INTEGER(iwp) :: nxrf !< INTEGER(iwp) :: nxr_on_file !< INTEGER(iwp) :: nync !< INTEGER(iwp) :: nynf !< INTEGER(iwp) :: nyn_on_file !< INTEGER(iwp) :: nysc !< INTEGER(iwp) :: nysf !< INTEGER(iwp) :: nys_on_file !< LOGICAL, INTENT(OUT) :: found REAL(wp), DIMENSION(nzb:nzt+1,nys_on_file-nbgp:nyn_on_file+nbgp,nxl_on_file-nbgp:nxr_on_file+nbgp) :: tmp_3d !< 3D array to temp store data found = .FALSE. IF ( ALLOCATED(chem_species) ) THEN DO lsp = 1, nspec !< for time-averaged chemical conc. spc_name_av = TRIM(chem_species(lsp)%name)//'_av' IF (restart_string(1:length) == TRIM(chem_species(lsp)%name) ) & THEN !< read data into tmp_3d IF ( k == 1 ) READ ( 13 ) tmp_3d !< fill ..%conc in the restart run chem_species(lsp)%conc(:,nysc-nbgp:nync+nbgp, & nxlc-nbgp:nxrc+nbgp) = & tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp) found = .TRUE. ELSEIF (restart_string(1:length) == spc_name_av ) THEN IF ( k == 1 ) READ ( 13 ) tmp_3d chem_species(lsp)%conc_av(:,nysc-nbgp:nync+nbgp, & nxlc-nbgp:nxrc+nbgp) = & tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp) found = .TRUE. ENDIF ENDDO ENDIF END SUBROUTINE chem_rrd_local ! !-------------------------------------------------------------------------------! !> Description: !> Calculation of horizontally averaged profiles !> This routine is called for every statistic region (sr) defined by the user, !> but at least for the region "total domain" (sr=0). !> quantities. !------------------------------------------------------------------------------! SUBROUTINE chem_statistics( mode, sr, tn ) USE arrays_3d USE indices USE kinds USE pegrid USE statistics USE user IMPLICIT NONE CHARACTER (LEN=*) :: mode !< INTEGER(iwp) :: i !< running index on x-axis INTEGER(iwp) :: j !< running index on y-axis INTEGER(iwp) :: k !< vertical index counter INTEGER(iwp) :: sr !< statistical region INTEGER(iwp) :: tn !< thread number INTEGER(iwp) :: n !< INTEGER(iwp) :: m !< INTEGER(iwp) :: lpr !< running index chem spcs ! REAL(wp), & ! DIMENSION(dots_num_palm+1:dots_max) :: & ! ts_value_l !< IF ( mode == 'profiles' ) THEN ! !-- Sample on how to calculate horizontally averaged profiles of user- !-- defined quantities. Each quantity is identified by the index !-- "pr_palm+#" where "#" is an integer starting from 1. These !-- user-profile-numbers must also be assigned to the respective strings !-- given by data_output_pr_cs in routine user_check_data_output_pr. !-- hom(:,:,:,:) = dim-1 = vertical level, dim-2= 1: met-species,2:zu/zw, dim-3 = quantity( e.g. ! w*pt*), dim-4 = statistical region. !$OMP DO DO i = nxl, nxr DO j = nys, nyn DO k = nzb, nzt+1 DO lpr = 1, cs_pr_count sums_l(k,pr_palm+lpr,tn) = sums_l(k,pr_palm+lpr,tn) + & chem_species(cs_pr_index(lpr))%conc(k,j,i) * & rmask(j,i,sr) * & MERGE( 1.0_wp, 0.0_wp, & BTEST( wall_flags_0(k,j,i), 22 ) ) ENDDO ENDDO ENDDO ENDDO ELSEIF ( mode == 'time_series' ) THEN CALL location_message( 'Time series not calculated for chemistry', .TRUE. ) ENDIF END SUBROUTINE chem_statistics ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine for swapping of timelevels for chemical species !> called out from subroutine swap_timelevel !------------------------------------------------------------------------------! SUBROUTINE chem_swap_timelevel (level) IMPLICIT none INTEGER,INTENT(IN) :: level !-- local variables INTEGER :: lsp IF ( level == 0 ) THEN DO lsp=1, nvar chem_species(lsp)%conc(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_1(:,:,:,lsp) chem_species(lsp)%conc_p(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_2(:,:,:,lsp) ENDDO ELSE DO lsp=1, nvar chem_species(lsp)%conc(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_2(:,:,:,lsp) chem_species(lsp)%conc_p(nzb:nzt+1,nysg:nyng,nxlg:nxrg) => spec_conc_1(:,:,:,lsp) ENDDO ENDIF RETURN END SUBROUTINE chem_swap_timelevel ! !------------------------------------------------------------------------------! ! ! Description: ! ------------ !> Subroutine to write restart data for chemistry model !------------------------------------------------------------------------------! SUBROUTINE chem_wrd_local IMPLICIT NONE INTEGER(iwp) :: lsp !< DO lsp = 1, nspec CALL wrd_write_string( TRIM( chem_species(lsp)%name )) WRITE ( 14 ) chem_species(lsp)%conc CALL wrd_write_string( TRIM( chem_species(lsp)%name )//'_av' ) WRITE ( 14 ) chem_species(lsp)%conc_av ENDDO END SUBROUTINE chem_wrd_local END MODULE chemistry_model_mod