PartMC  2.8.0
tchem_interface.F90
Go to the documentation of this file.
1 ! Copyright (C) 2024 Jeff Curtis
2 ! Licensed under the GNU General Public License version 2 or (at your
3 ! option) any later version. See the file COPYING for details.
4 
5 !> \file
6 !> The pmc_tchem_interface module.
7 
8 !> An interface between PartMC and TChem
10 
11  use pmc_aero_data
13  use pmc_aero_state
14  use pmc_constants
15  use pmc_gas_data
16  use pmc_gas_state
17 #ifdef PMC_USE_TCHEM
18  use iso_c_binding
19 #endif
21 
22 interface
23  subroutine initialize(arg_chemfile, arg_aerofile, arg_numericsfile, &
24  n_batch) &
25  bind(c, name="initialize")
26  use iso_c_binding
27  character(kind=c_char), intent(in) :: arg_chemfile(*)
28  character(kind=c_char), intent(in) :: arg_aerofile(*)
29  character(kind=c_char), intent(in) :: arg_numericsfile(*)
30  integer(c_int), intent(in), value :: n_batch
31  end subroutine initialize
32  subroutine finalize() bind(c, name="finalize")
33  end subroutine finalize
34  function tchem_getnumberofspecies() bind(c, name="TChem_getNumberOfSpecies")
35  use iso_c_binding
36  integer(kind=c_int) :: tchem_getnumberofspecies
37  end function
38  function tchem_getlengthofstatevector() bind(c, &
39  name="TChem_getLengthOfStateVector")
40  use iso_c_binding
41  integer(kind=c_int) :: tchem_getlengthofstatevector
42  end function
43  subroutine tchem_getstatevector(array, i_batch) bind(c, &
44  name="TChem_getStateVector")
45  use iso_c_binding
46  real(kind=c_double) :: array(*)
47  integer(c_int), value :: i_batch
48  end subroutine
49  subroutine tchem_setstatevector(array, i_batch) bind(c, &
50  name="TChem_setStateVector")
51  use iso_c_binding
52  real(kind=c_double) :: array(*)
53  integer(c_int), value :: i_batch
54  end subroutine
55  integer(kind=c_size_t) function tchem_getspeciesname(index, result, &
56  buffer_size) bind(C, name="TChem_getSpeciesName")
57  use iso_c_binding
58  integer(kind=c_int), intent(in) :: index
59  character(kind=c_char), intent(out) :: result(*)
60  integer(kind=c_size_t), intent(in), value :: buffer_size
61  end function
62  subroutine tchem_dotimestep(del_t) bind(C, name="TChem_doTimestep")
63  use iso_c_binding
64  real(kind=c_double), intent(in) :: del_t
65  end subroutine
66 end interface
67 
68 contains
69 
70 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
71 #ifdef PMC_USE_TCHEM
72  !> Run the CAMP module for the current PartMC state
73  subroutine pmc_tchem_interface_solve(env_state, aero_data, aero_state, &
74  gas_data, gas_state, del_t)
75 
76  !> Environment data.
77  type(env_state_t), intent(in) :: env_state
78  !> Aerosol data.
79  type(aero_data_t), intent(in) :: aero_data
80  !> Aerosol state.
81  type(aero_state_t), intent(inout) :: aero_state
82  !> Gas data.
83  type(gas_data_t), intent(in) :: gas_data
84  !> Gas state.
85  type(gas_state_t), intent(inout) :: gas_state
86  !> Time step (s).
87  real(kind=dp), intent(in) :: del_t
88 
89  call tchem_from_partmc(aero_data, aero_state, gas_data, gas_state, &
90  env_state)
91 
92  call tchem_timestep(del_t)
93 
94  call tchem_to_partmc(aero_data, aero_state, gas_data, gas_state, env_state)
95 
96  end subroutine pmc_tchem_interface_solve
97 
98 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
99 
100  !> Initialize TChem and PartMC gas and aerosol data.
101  subroutine pmc_tchem_initialize(gas_config_filename, aero_config_filename, &
102  solver_config_filename, gas_data, aero_data, n_grid_cells)
103  use iso_c_binding
104 
105  !> Gas configuration filename.
106  character(len=*), intent(in) :: gas_config_filename
107  !> Aerosol configuration filename.
108  character(len=*), intent(in) :: aero_config_filename
109  !> Numerical configuration filename.
110  character(len=*), intent(in) :: solver_config_filename
111  !> Gas data.
112  type(gas_data_t), intent(inout) :: gas_data
113  !> Aerosol data.
114  type(aero_data_t), intent(inout) :: aero_data
115  !> Number of cells to solve.
116  integer, intent(in) :: n_grid_cells
117 
118  integer(kind=c_int) :: nSpec, nAeroSpec
119  integer :: n_species
120  integer :: i
121  real(kind=c_double), dimension(:), allocatable :: array
122  character(:), allocatable :: val
123 
124  ! initialize the model
125  call tchem_initialize(trim(gas_config_filename), &
126  trim(aero_config_filename), trim(solver_config_filename), &
127  n_grid_cells)
128 
129  ! Get size that gas_data should be
130  nspec = tchem_getnumberofspecies()
131  call ensure_string_array_size(gas_data%name, nspec)
132 
133  ! Populate gas_data with gas species from TChem
134  do i = 1,nspec
135  val = tchem_species_name(i-1)
136  gas_data%name(i) = trim(val)
137  end do
138 
139  ! For output and MPI, this needs to be allocated (for now)
140  allocate(gas_data%mosaic_index(gas_data_n_spec(gas_data)))
141  gas_data%mosaic_index(:) = 0
142 
143  ! TODO: Create aero_data based on TChem input.
144  ! From TChem we need:
145  ! Species names
146  ! Species properties - density, kappa, molecular weight
147  ! n_species = 10
148  ! call ensure_string_array_size(aero_data%name, n_species)
149  ! call ensure_integer_array_size(aero_data%mosaic_index, n_species)
150  ! call ensure_real_array_size(aero_data%wavelengths, n_swbands)
151  ! call ensure_real_array_size(aero_data%density, n_species)
152  ! call ensure_integer_array_size(aero_data%num_ions, n_species)
153  ! call ensure_real_array_size(aero_data%molec_weight, n_species)
154  ! call ensure_real_array_size(aero_data%kappa, n_species)
155  !do i = 1,n_species
156  !end do
157 
158  end subroutine pmc_tchem_initialize
159 
160 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
161 
162  !> Clean up TChem.
163  subroutine pmc_tchem_cleanup()
164 
165  call finalize()
166 
167  end subroutine pmc_tchem_cleanup
168 
169 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
170 
171  !> Map all data TChem -> PartMC.
172  subroutine tchem_to_partmc(aero_data, aero_state, gas_data, gas_state, &
173  env_state)
174 
175  !> Aerosol data.
176  type(aero_data_t), intent(in) :: aero_data
177  !> Aerosol state.
178  type(aero_state_t), intent(inout) :: aero_state
179  !> Gas data.
180  type(gas_data_t), intent(in) :: gas_data
181  !> Gas state.
182  type(gas_state_t), intent(inout) :: gas_state
183  !> Environment state.
184  type(env_state_t), intent(in) :: env_state
185 
186  integer(c_int) :: nSpec, stateVecDim
187  integer :: i_part
188  real(kind=c_double), dimension(:), allocatable :: statevector
189 
190  ! Get gas array
191  statevecdim = tchem_getlengthofstatevector()
192  nspec = tchem_getnumberofspecies()
193  allocate(statevector(statevecdim))
194  call tchem_getstatevector(statevector, 0)
195 
196  gas_state%mix_rat = 0.0
197  ! Convert from ppm to ppb.
198  gas_state%mix_rat = statevector(4:nspec+3) * 1000.d0
199 
200  ! Map aerosols
201  do i_part = 1,aero_state_n_part(aero_state)
202 
203  end do
204 
205  end subroutine tchem_to_partmc
206 
207 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
208 
209  !> Map all data PartMC -> TChem.
210  subroutine tchem_from_partmc(aero_data, aero_state, gas_data, gas_state, &
211  env_state)
212 
213  !> Aerosol data.
214  type(aero_data_t), intent(in) :: aero_data
215  !> Aerosol state.
216  type(aero_state_t), intent(in) :: aero_state
217  !> Gas data.
218  type(gas_data_t), intent(in) :: gas_data
219  !> Gas State.
220  type(gas_state_t), intent(inout) :: gas_state
221  !> Environment state.
222  type(env_state_t), intent(in) :: env_state
223 
224  real(kind=dp), allocatable :: statevector(:)
225  integer :: stateVecDim
226  integer :: i_part
227  integer :: i_water
228 
229  ! Get size of stateVector
230  statevecdim = tchem_getlengthofstatevector()
231  allocate(statevector(statevecdim))
232  ! First three elements are density, pressure and temperature
233  statevector(1) = env_state_air_den(env_state)
234  statevector(2) = env_state%pressure
235  statevector(3) = env_state%temp
236 
237  ! PartMC uses relative humidity and not H2O mixing ratio.
238  ! Equation 1.10 from Seinfeld and Pandis - Second Edition.
239  i_water = gas_data_spec_by_name(gas_data, "H2O")
240  gas_state%mix_rat(i_water) = env_state_rel_humid_to_mix_rat(env_state)
241  ! Add gas species to state vector. Convert from ppb to ppm.
242  statevector(4:gas_data_n_spec(gas_data)+3) = gas_state%mix_rat / 1000.d0
243 
244  ! TODO: Map aerosols
245  do i_part = 1,aero_state_n_part(aero_state)
246 
247  end do
248 
249  call tchem_setstatevector(statevector, 0)
250 
251  end subroutine tchem_from_partmc
252 
253 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
254 
255  !> Do a single timestep of TChem chemistry.
256  subroutine tchem_timestep(del_t)
257  use iso_c_binding
258 
259  !> Time step (s).
260  real(kind=c_double) :: del_t
261 
262  call tchem_dotimestep(del_t)
263 
264  end subroutine tchem_timestep
265 
266 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
267 
268  !> Initialize TChem.
269  subroutine tchem_initialize(chemFile, aeroFile, NumericsFile, n_batch)
270  use iso_c_binding
271 
272  !> Chemistry configuration file.
273  character(kind=c_char,len=*), intent(in) :: chemFile
274  !> Chemistry configuration file.
275  character(kind=c_char,len=*), intent(in) :: aeroFile
276  !> Chemistry configuration file.
277  character(kind=c_char,len=*), intent(in) :: numericsFile
278  !> Number of systems to solve.
279  integer(kind=c_int), intent(in) :: n_batch
280 
281  call initialize(chemfile//c_null_char, aerofile//c_null_char, &
282  numericsfile//c_null_char, n_batch)
283 
284  end subroutine tchem_initialize
285 
286 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
287 
288  !> Get species name from TChem for a given index.
289  function tchem_species_name(i_spec) result(species_name)
290  use iso_c_binding
291 
292  ! Species name.
293  character(:), allocatable :: species_name
294 
295  integer(kind=c_int), intent(in) :: i_spec
296  character(kind=c_char, len=:), allocatable :: cbuf
297  integer(kind=c_size_t) :: N
298 
299  allocate(character(256) :: cbuf)
300  n = len(cbuf)
301  n = tchem_getspeciesname(i_spec, cbuf, n)
302  allocate(character(N) :: species_name)
303  species_name = cbuf(:n)
304 
305  end function tchem_species_name
306 #endif
307 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
308 
309 end module pmc_tchem_interface
pmc_gas_data::gas_data_t
Constant gas data.
Definition: gas_data.F90:35
pmc_aero_state::aero_state_n_part
elemental integer function aero_state_n_part(aero_state)
Return the current number of particles.
Definition: aero_state.F90:94
pmc_aero_particle
The aero_particle_t structure and associated subroutines.
Definition: aero_particle.F90:9
pmc_gas_data
The gas_data_t structure and associated subroutines.
Definition: gas_data.F90:9
pmc_util::warn_assert_msg
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
Definition: util.F90:60
pmc_util::die_msg
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:135
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
pmc_aero_state
The aero_state_t structure and assocated subroutines.
Definition: aero_state.F90:9
pmc_gas_state
The gas_state_t structure and associated subroutines.
Definition: gas_state.F90:9
pmc_tchem_interface::finalize
Definition: tchem_interface.F90:32
pmc_util::assert_msg
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:78
pmc_gas_state::gas_state_t
Current state of the gas mixing ratios in the system.
Definition: gas_state.F90:33
pmc_tchem_interface
An interface between PartMC and TChem.
Definition: tchem_interface.F90:9
pmc_aero_data::aero_data_t
Aerosol material properties and associated data.
Definition: aero_data.F90:55
pmc_constants
Physical constants.
Definition: constants.F90:9
pmc_gas_data::gas_data_spec_by_name
integer function gas_data_spec_by_name(gas_data, name)
Returns the number of the species in gas with the given name, or returns 0 if there is no such specie...
Definition: gas_data.F90:126
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_gas_data::gas_data_n_spec
elemental integer function gas_data_n_spec(gas_data)
Return the number of gas species.
Definition: gas_data.F90:109
pmc_aero_data
The aero_data_t structure and associated subroutines.
Definition: aero_data.F90:9
pmc_tchem_interface::initialize
Definition: tchem_interface.F90:23
pmc_aero_state::aero_state_t
The current collection of aerosol particles.
Definition: aero_state.F90:69