CAMP 1.0.0
Chemistry Across Multiple Phases
camp_solver_data.F90
Go to the documentation of this file.
1! Copyright (C) 2021 Barcelona Supercomputing Center and University of
2! Illinois at Urbana-Champaign
3! SPDX-License-Identifier: MIT
4
5!> \file
6!> The camp_camp_solver_data module.
7
8!> The camp_solver_data_t structure and associated subroutines.
10
14 use camp_constants, only : i_kind, dp
22 use camp_util, only : assert_msg, to_string, &
24
25 use iso_c_binding
26
27 implicit none
28 private
29
30 public :: camp_solver_data_t
31
32 !> Default relative tolerance for integration
33 real(kind=dp), parameter :: camp_solver_default_rel_tol = 1.0d-8
34 !> Default max number of integration steps
35 integer(kind=i_kind), parameter :: camp_solver_default_max_steps = 10000
36 !> Default maximum number of integration convergence failures
37 integer(kind=i_kind), parameter :: camp_solver_default_max_conv_fails = 1000
38
39 !> Result code indicating successful completion
40 integer, parameter :: camp_solver_success = 0
41
42 !> Interface to c ODE solver functions
43 interface
44 !> Get a new solver
45 type(c_ptr) function solver_new(n_state_var, n_cells, var_type, &
46 n_rxn, n_rxn_int_param, n_rxn_float_param, &
47 n_rxn_env_param, n_aero_phase, n_aero_phase_int_param, &
48 n_aero_phase_float_param, n_aero_rep, &
49 n_aero_rep_int_param, n_aero_rep_float_param, &
50 n_aero_rep_env_param, n_sub_model, n_sub_model_int_param,&
51 n_sub_model_float_param, n_sub_model_env_param) bind (c)
52 use iso_c_binding
53 !> Number of variables on the state array per grid cell
54 !! (including const, PSSA, etc.)
55 integer(kind=c_int), value :: n_state_var
56 !> Number of cells to compute
57 integer(kind=c_int), value :: n_cells
58 !> Pointer to array of state variable types (solver, constant, PSSA)
59 type(c_ptr), value :: var_type
60 !> Number of reactions to solve
61 integer(kind=c_int), value :: n_rxn
62 !> Total number of integer parameters for all reactions
63 integer(kind=c_int), value :: n_rxn_int_param
64 !> Total number of floating-point parameters for all reactions
65 integer(kind=c_int), value :: n_rxn_float_param
66 !> Total number of environment-dependent parameters for all reactions
67 integer(kind=c_int), value :: n_rxn_env_param
68 !> Number of aerosol phases
69 integer(kind=c_int), value :: n_aero_phase
70 !> Total number of integer parameters for all aerosol phases
71 integer(kind=c_int), value :: n_aero_phase_int_param
72 !> Total number of floating-point parameters for all aerosol phases
73 integer(kind=c_int), value :: n_aero_phase_float_param
74 !> Number of aerosol representations
75 integer(kind=c_int), value :: n_aero_rep
76 !> Total number of integer parameters for all aerosol representations
77 integer(kind=c_int), value :: n_aero_rep_int_param
78 !> Total number of floating-point parameters for all aerosol
79 !! representations
80 integer(kind=c_int), value :: n_aero_rep_float_param
81 !> Total number of environment-dependent parameters for all aerosol
82 !> representations
83 integer(kind=c_int), value :: n_aero_rep_env_param
84 !> Number of sub models
85 integer(kind=c_int), value :: n_sub_model
86 !> Total number of integer parameters for all sub models
87 integer(kind=c_int), value :: n_sub_model_int_param
88 !> Total number of floating-point parameters for all sub models
89 integer(kind=c_int), value :: n_sub_model_float_param
90 !> Total number of environment-dependent parameters for all sub models
91 integer(kind=c_int), value :: n_sub_model_env_param
92 end function solver_new
93
94 !> Solver initialization
95 subroutine solver_initialize(solver_data, abs_tol, rel_tol, max_steps, &
96 max_conv_fails) bind (c)
97 use iso_c_binding
98 !> Pointer to a SolverData object
99 type(c_ptr), value :: solver_data
100 !> Pointer to array of absolute toleracnes
101 type(c_ptr), value :: abs_tol
102 !> Relative integration tolerance
103 real(kind=c_double), value :: rel_tol
104 !> Maximum number of internal integration steps
105 integer(kind=c_int), value :: max_steps
106 !> Maximum number of convergence failures
107 integer(kind=c_int), value :: max_conv_fails
108 end subroutine solver_initialize
109
110#ifdef CAMP_DEBUG
111 !> Set the debug output flag for the solver
112 integer(kind=c_int) function solver_set_debug_out(solver_data, &
113 do_output) bind (c)
114 use iso_c_binding
115 !> Pointer to a SolverData object
116 type(c_ptr), value :: solver_data
117 !> Flag indicating whether to output debugging information
118 integer(kind=c_int), value :: do_output
119 end function solver_set_debug_out
120
121 !> Set the Jacobian evaluation flag for the solver
122 integer(kind=c_int) function solver_set_eval_jac(solver_data, &
123 eval_Jac) bind (c)
124 use iso_c_binding
125 !> Pointer to a SolverData object
126 type(c_ptr), value :: solver_data
127 !> Flag indicating whether to evaluate the Jacobian during solving
128 integer(kind=c_int), value :: eval_Jac
129 end function solver_set_eval_jac
130#endif
131
132 !> Run the solver
133 integer(kind=c_int) function solver_run(solver_data, state, env, &
134 t_initial, t_final) bind (c)
135 use iso_c_binding
136 !> Pointer to the initialized solver data
137 type(c_ptr), value :: solver_data
138 !> Pointer to the state array
139 type(c_ptr), value :: state
140 !> Pointer to the environmental state array
141 type(c_ptr), value :: env
142 !> Initial time (s)
143 real(kind=c_double), value :: t_initial
144 !> Final time (s)
145 real(kind=c_double), value :: t_final
146 end function solver_run
147
148 !> Reset the solver function timers
149 subroutine solver_reset_timers( solver_data ) bind(c)
150 use iso_c_binding
151 !> Pointer to the solver data
152 type(c_ptr), value :: solver_data
153 end subroutine solver_reset_timers
154
155 !> Get the solver statistics
156 subroutine solver_get_statistics( solver_data, solver_flag, num_steps, &
157 RHS_evals, LS_setups, error_test_fails, NLS_iters, &
158 NLS_convergence_fails, DLS_Jac_evals, DLS_RHS_evals, &
159 last_time_step__s, next_time_step__s, Jac_eval_fails, &
160 RHS_evals_total, Jac_evals_total, RHS_time__s, &
161 Jac_time__s, max_loss_precision) bind (c)
162 use iso_c_binding
163 !> Pointer to the solver data
164 type(c_ptr), value :: solver_data
165 !> Last flag returned by the solver
166 type(c_ptr), value :: solver_flag
167 !> Number of steps
168 type(c_ptr), value :: num_steps
169 !> Right-hand side evaluations
170 type(c_ptr), value :: RHS_evals
171 !> Linear solver setups
172 type(c_ptr), value :: LS_setups
173 !> Error test failures
174 type(c_ptr), value :: error_test_fails
175 !> Non-Linear solver iterations
176 type(c_ptr), value :: NLS_iters
177 !> Non-Linear solver failures
178 type(c_ptr), value :: NLS_convergence_fails
179 !> Direct Linear Solver Jacobian evaluations
180 type(c_ptr), value :: DLS_Jac_evals
181 !> Direct Linear Solver right-hand side evaluations
182 type(c_ptr), value :: DLS_RHS_evals
183 !> Last time step [s]
184 type(c_ptr), value :: last_time_step__s
185 !> Next time step [s]
186 type(c_ptr), value :: next_time_step__s
187 !> Number of Jacobian evaluation failures
188 type(c_ptr), value :: Jac_eval_fails
189 !> Total number of calls to `f()`
190 type(c_ptr), value :: RHS_evals_total
191 !> Total number of calls to `Jac()`
192 type(c_ptr), value :: Jac_evals_total
193 !> Compute time for calls to `f()`
194 type(c_ptr), value :: RHS_time__s
195 !> Compute time for calls to `Jac()`
196 type(c_ptr), value :: Jac_time__s
197 !> Maximum loss of precision on last call the f()
198 type(c_ptr), value :: max_loss_precision
199 end subroutine solver_get_statistics
200
201 !> Add condensed reaction data to the solver data block
202 subroutine rxn_add_condensed_data(rxn_type, n_int_param, &
203 n_float_param, n_env_param, int_param, float_param, &
204 solver_data) bind (c)
205 use iso_c_binding
206 !> Reaction type
207 integer(kind=c_int), value :: rxn_type
208 !> Number of integer parameters to add
209 integer(kind=c_int), value :: n_int_param
210 !> Number of floating-point parameters to add
211 integer(kind=c_int), value :: n_float_param
212 !> Number of environment-dependent parameters to add
213 integer(kind=c_int), value :: n_env_param
214 !> Pointer to the integer parameter array
215 type(c_ptr), value :: int_param
216 !> Pointer to the floating-point parameter array
217 type(c_ptr), value :: float_param
218 !> Pointer to the solver data
219 type(c_ptr), value :: solver_data
220 end subroutine rxn_add_condensed_data
221
222 !> Update reaction data
223 subroutine rxn_update_data(cell_id, rxn_id, rxn_type, update_data, &
224 solver_data) bind(c)
225 use iso_c_binding
226 !> Grid cell to update
227 integer(kind=c_int), value :: cell_id
228 !> Reaction id
229 integer(kind=c_int) :: rxn_id
230 !> Reaction type to updateto update
231 integer(kind=c_int), value :: rxn_type
232 !> Data required by reaction for updates
233 type(c_ptr), value :: update_data
234 !> Solver data
235 type(c_ptr), value :: solver_data
236 end subroutine rxn_update_data
237
238 !> Print the solver data
239 subroutine rxn_print_data(solver_data) bind(c)
240 use iso_c_binding
241 !> Solver data
242 type(c_ptr), value :: solver_data
243 end subroutine rxn_print_data
244
245 !> Add condensed sub model data to the solver data block
246 subroutine sub_model_add_condensed_data(sub_model_type, n_int_param, &
247 n_float_param, n_env_param, int_param, float_param, &
248 solver_data) bind(c)
249 use iso_c_binding
250 !> Sub model type
251 integer(kind=c_int), value :: sub_model_type
252 !> Number of integer parameters to add
253 integer(kind=c_int), value :: n_int_param
254 !> Number of floating-point parameters to add
255 integer(kind=c_int), value :: n_float_param
256 !> Number of environment-dependent parameters to add
257 integer(kind=c_int), value :: n_env_param
258 !> Pointer to the integer parameter array
259 type(c_ptr), value :: int_param
260 !> Pointer to the floating-point parameter array
261 type(c_ptr), value :: float_param
262 !> Pointer to the solver data
263 type(c_ptr), value :: solver_data
264 end subroutine sub_model_add_condensed_data
265
266 !> Update reaction data
267 subroutine sub_model_update_data(cell_id, sub_model_id, sub_model_type, &
268 update_data, solver_data) bind(c)
269 use iso_c_binding
270 !> Grid cell to update
271 integer(kind=c_int), value :: cell_id
272 !> Sub model solver id
273 integer(kind=c_int) :: sub_model_id
274 !> Reaction type to updateto update
275 integer(kind=c_int), value :: sub_model_type
276 !> Data required by reaction for updates
277 type(c_ptr), value :: update_data
278 !> Solver data
279 type(c_ptr), value :: solver_data
280 end subroutine sub_model_update_data
281
282 !> Print the solver data
283 subroutine sub_model_print_data(solver_data) bind(c)
284 use iso_c_binding
285 !> Solver data
286 type(c_ptr), value :: solver_data
287 end subroutine sub_model_print_data
288
289 !> Add condensed aerosol phase data to the solver data block
290 subroutine aero_phase_add_condensed_data(n_int_param, n_float_param, &
291 int_param, float_param, solver_data) bind(c)
292 use iso_c_binding
293 !> Number of integer parameters to add
294 integer(kind=c_int), value :: n_int_param
295 !> Number of floating-point parameters to add
296 integer(kind=c_int), value :: n_float_param
297 !> Pointer to the integer parameter array
298 type(c_ptr), value :: int_param
299 !> Pointer to the floating-point parameter array
300 type(c_ptr), value :: float_param
301 !> Pointer to the solver data
302 type(c_ptr), value :: solver_data
303 end subroutine aero_phase_add_condensed_data
304
305 !> Print the solver data
306 subroutine aero_phase_print_data(solver_data) bind(c)
307 use iso_c_binding
308 !> Solver data
309 type(c_ptr), value :: solver_data
310 end subroutine aero_phase_print_data
311
312 !> Add condensed aerosol representation data to the solver data block
313 subroutine aero_rep_add_condensed_data(aero_rep_type, n_int_param, &
314 n_float_param, n_env_param, int_param, float_param, &
315 solver_data) bind(c)
316 use iso_c_binding
317 !> Aerosol representation type
318 integer(kind=c_int), value :: aero_rep_type
319 !> Number of integer parameters to add
320 integer(kind=c_int), value :: n_int_param
321 !> Number of floating-point parameters to add
322 integer(kind=c_int), value :: n_float_param
323 !> Number of environment-dependent parameters to add
324 integer(kind=c_int), value :: n_env_param
325 !> Pointer to the integer parameter array
326 type(c_ptr), value :: int_param
327 !> Pointer to the floating-point parameter array
328 type(c_ptr), value :: float_param
329 !> Pointer to the solver data
330 type(c_ptr), value :: solver_data
331 end subroutine aero_rep_add_condensed_data
332
333 !> Update aerosol representation data
334 subroutine aero_rep_update_data(cell_id, aero_rep_id, aero_rep_type, &
335 update_data, solver_data) bind(c)
336 use iso_c_binding
337 !> Grid cell to update
338 integer(kind=c_int), value :: cell_id
339 !> Aerosol representation solver id
340 integer(kind=c_int) :: aero_rep_id
341 !> Aerosol representation type to updateto update
342 integer(kind=c_int), value :: aero_rep_type
343 !> Data required by aerosol representation for updates
344 type(c_ptr), value :: update_data
345 !> Solver data
346 type(c_ptr), value :: solver_data
347 end subroutine aero_rep_update_data
348
349 !> Print the aerosol representation data
350 subroutine aero_rep_print_data(solver_data) bind(c)
351 use iso_c_binding
352 !> Pointer to the solver data
353 type(c_ptr), value :: solver_data
354 end subroutine aero_rep_print_data
355
356 !> Free the memory associated with a solver
357 pure subroutine solver_free(solver_data) bind(c)
358 use iso_c_binding
359 !> Pointer to the solver data
360 type(c_ptr), value, intent(in) :: solver_data
361 end subroutine solver_free
362
363 end interface
364
365 !> Solver data
366 !!
367 !! Acts as the interface between the camp-chem module and the solver.
368 !! Instances of the type hold a pointer to a solver c object and provide
369 !! functions to initialize the solver with model data and run the solver
370 !! over a specified time step.
372 private
373 !> C Solver object
374 type(c_ptr), public :: solver_c_ptr
375 !> Relative tolerance for the integration
376 real(kind=dp), public :: rel_tol = camp_solver_default_rel_tol
377 !> Maximum number of timesteps
378 integer(kind=i_kind), public :: max_steps = camp_solver_default_max_steps
379 !> Maximum number of convergence failures
380 integer(kind=i_kind), public :: max_conv_fails = &
382 !> Flag indicating whether the solver was intialized
383 logical :: initialized = .false.
384 contains
385 !> Initialize the solver
386 procedure :: initialize
387 !> Update sub-model data
389 !> Update reactions data
390 procedure :: update_rxn_data
391 !> Update aerosol representation data
393 !> Integrate over a given time step
394 procedure :: solve
395 !> Reset the solver function timers
396 procedure, private :: reset_timers
397 !> Get the solver statistics from the last run
398 procedure, private :: get_solver_stats
399 !> Checks whether a solver is available
401 !> Print the solver data
402 procedure :: print => do_print
403 !> Finalize the solver data
404 final :: finalize
405 end type camp_solver_data_t
406
407 ! Constructor for camp_solver_data_t
408 interface camp_solver_data_t
409 procedure :: constructor
410 end interface camp_solver_data_t
411
412contains
413
414!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
415
416 !> Constructor for camp_solver_data_t
417 function constructor() result (new_obj)
418
419 !> New solver variable
420 type(camp_solver_data_t), pointer :: new_obj
421
422 !> Allocate space for the new object
423 allocate(new_obj)
424
425 end function constructor
426
427!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
428
429 !> Initialize the solver
430 subroutine initialize(this, var_type, abs_tol, mechanisms, aero_phases, &
431 aero_reps, sub_models, rxn_phase, n_cells)
432
433 !> Solver data
434 class(camp_solver_data_t), intent(inout) :: this
435 !> Variable type for each species in the state array. This array must be
436 !! of the same length as the state array.
437 integer(kind=i_kind), allocatable, intent(in) :: var_type(:)
438 !> Absolute tolerance for each species in the state array. This array must
439 !! be of the same length as the state array. Values for CONST and PSSA
440 !! species will be ignored by the solver.
441 real(kind=dp), allocatable, intent(in) :: abs_tol(:)
442 !> Mechanisms to include in solver
443 type(mechanism_data_ptr), pointer, intent(in) :: mechanisms(:)
444 !> Aerosol phases to include
445 type(aero_phase_data_ptr), pointer, intent(in) :: aero_phases(:)
446 !> Aerosol representations to include
447 type(aero_rep_data_ptr), pointer, intent(in) :: aero_reps(:)
448 !> Sub models to include
449 type(sub_model_data_ptr), pointer, intent(in) :: sub_models(:)
450 !> Reactions phase to solve -- gas, aerosol, or both (default)
451 !! Use parameters in camp_rxn_data to specify phase:
452 !! GAS_RXN, AERO_RXN, GAS_AERO_RXN
453 integer(kind=i_kind), intent(in) :: rxn_phase
454 !> Number of cells to compute
455 integer(kind=i_kind), optional :: n_cells
456
457 ! Variable types
458 integer(kind=c_int), pointer :: var_type_c(:)
459 ! Absolute tolerances
460 real(kind=c_double), pointer :: abs_tol_c(:)
461 ! Indices for iteration
462 integer(kind=i_kind) :: i_mech, i_rxn, i_aero_phase, i_aero_rep, &
463 i_sub_model
464 ! Reaction pointer
465 class(rxn_data_t), pointer :: rxn
466 ! Reaction factory object for getting reaction type
467 type(rxn_factory_t) :: rxn_factory
468 ! Aerosol phase pointer
469 type(aero_phase_data_t), pointer :: aero_phase
470 ! Aerosol representation pointer
471 class(aero_rep_data_t), pointer :: aero_rep
472 ! Aerosol representation factory object for getting aerosol
473 ! representation type
474 type(aero_rep_factory_t) :: aero_rep_factory
475 ! Sub model pointer
476 class(sub_model_data_t), pointer :: sub_model
477 ! Sub model factory for getting sub model type
478 type(sub_model_factory_t) :: sub_model_factory
479 ! Integer parameters being transfered
480 integer(kind=c_int), pointer :: int_param(:)
481 ! Floating point parameters being transfered
482 real(kind=c_double), pointer :: float_param(:)
483 ! Number of reactions
484 integer(kind=c_int) :: n_rxn
485 ! Number of integer reaction parameters
486 integer(kind=c_int) :: n_rxn_int_param
487 ! Number of floating-point reaction parameters
488 integer(kind=c_int) :: n_rxn_float_param
489 ! Number of environment-dependent reaction parameters
490 integer(kind=c_int) :: n_rxn_env_param
491 ! Number of aerosol phases
492 integer(kind=c_int) :: n_aero_phase
493 ! Number of integer aerosol phase parameters
494 integer(kind=c_int) :: n_aero_phase_int_param
495 ! Number of floating-point aerosol phase parameters
496 integer(kind=c_int) :: n_aero_phase_float_param
497 ! Number of aerosol representations
498 integer(kind=c_int) :: n_aero_rep
499 ! Number of integer aerosol representation parameters
500 integer(kind=c_int) :: n_aero_rep_int_param
501 ! Number of floating-point aerosol representation parameters
502 integer(kind=c_int) :: n_aero_rep_float_param
503 ! Number of environment-dependent aerosol representation parameters
504 integer(kind=c_int) :: n_aero_rep_env_param
505 ! Number of sub models
506 integer(kind=c_int) :: n_sub_model
507 ! Number of integer sub model parameters
508 integer(kind=c_int) :: n_sub_model_int_param
509 ! Number of floating-point sub model parameters
510 integer(kind=c_int) :: n_sub_model_float_param
511 ! Number of environment-dependent sub model parameters
512 integer(kind=c_int) :: n_sub_model_env_param
513 ! Number of cells to compute
514 integer(kind=c_int) :: l_n_cells
515
516 if (present(n_cells)) then
517 l_n_cells = n_cells
518 else
519 l_n_cells = 1
520 end if
521
522 ! Make sure the variable type and absolute tolerance arrays are of
523 ! equal length
524 call assert_msg(825843466, size(abs_tol).eq.size(var_type), &
525 "Mismatched absolute tolerance and variable type arrays: "// &
526 "abs_tol size: "//trim(to_string(size(abs_tol)))// &
527 "; var_type: "//trim(to_string(size(var_type))))
528
529 ! Set the absolute tolerance and variable type arrays
530 allocate(var_type_c(size(var_type)))
531 allocate(abs_tol_c(size(abs_tol)))
532 var_type_c(:) = int(var_type(:), kind=c_int)
533 abs_tol_c(:) = real(abs_tol(:), kind=c_double)
534
535 ! Initialize the counters
536 n_rxn = 0
537 n_rxn_int_param = 0
538 n_rxn_float_param = 0
539 n_rxn_env_param = 0
540
541 ! Calculate the number of reactions and the size of the condensed data
542 do i_mech=1, size(mechanisms)
543 do i_rxn=1, mechanisms(i_mech)%val%size()
544 rxn => mechanisms(i_mech)%val%get_rxn(i_rxn)
545 select case (rxn%rxn_phase)
546 case (gas_rxn)
547 if (rxn_phase.eq.aero_rxn) cycle
548 case (aero_rxn)
549 if (rxn_phase.eq.gas_rxn) cycle
550 case (gas_aero_rxn)
551 if (rxn_phase.eq.gas_rxn) cycle
552 end select
553 n_rxn = n_rxn + 1
554 n_rxn_int_param = n_rxn_int_param + size(rxn%condensed_data_int)
555 n_rxn_float_param = n_rxn_float_param + size(rxn%condensed_data_real)
556 n_rxn_env_param = n_rxn_env_param + rxn%num_env_params
557 end do
558 end do
559 rxn => null()
560
561 ! Initialize the aerosol phase counters
562 n_aero_phase = size(aero_phases)
563 n_aero_phase_int_param = 0
564 n_aero_phase_float_param = 0
565
566 ! Calculate the size of the aerosol phases condensed data
567 do i_aero_phase=1, n_aero_phase
568 aero_phase => aero_phases(i_aero_phase)%val
569 n_aero_phase_int_param = n_aero_phase_int_param + &
570 size(aero_phase%condensed_data_int)
571 n_aero_phase_float_param = n_aero_phase_float_param + &
572 size(aero_phase%condensed_data_real)
573 end do
574 aero_phase => null()
575
576 ! Initialize the aerosol representation counters
577 n_aero_rep = size(aero_reps)
578 n_aero_rep_int_param = 0
579 n_aero_rep_float_param = 0
580 n_aero_rep_env_param = 0
581
582 ! Calculate the size of the aerosol representations condensed data
583 do i_aero_rep=1, n_aero_rep
584 aero_rep => aero_reps(i_aero_rep)%val
585 n_aero_rep_int_param = n_aero_rep_int_param + &
586 size(aero_rep%condensed_data_int)
587 n_aero_rep_float_param = n_aero_rep_float_param + &
588 size(aero_rep%condensed_data_real)
589 n_aero_rep_env_param = n_aero_rep_env_param + &
590 aero_rep%num_env_params
591 end do
592 aero_rep => null()
593
594 ! Initialize the sub model counters
595 n_sub_model = size(sub_models)
596 n_sub_model_int_param = 0
597 n_sub_model_float_param = 0
598 n_sub_model_env_param = 0
599
600 ! Calculate the size of the sub model condensed data
601 do i_sub_model=1, n_sub_model
602 sub_model => sub_models(i_sub_model)%val
603 n_sub_model_int_param = n_sub_model_int_param + &
604 size(sub_model%condensed_data_int)
605 n_sub_model_float_param = n_sub_model_float_param + &
606 size(sub_model%condensed_data_real)
607 n_sub_model_env_param = n_sub_model_env_param + sub_model%num_env_params
608 end do
609 sub_model => null()
610
611 ! Get a new solver object
612 this%solver_c_ptr = solver_new( &
613 int(size(var_type_c), kind=c_int), & ! Size of the state variable
614 l_n_cells, & ! # of cells computed at once
615 c_loc(var_type_c), & ! Variable types
616 n_rxn, & ! # of reactions
617 n_rxn_int_param, & ! # of rxn data int params
618 n_rxn_float_param, & ! # of rxn data real params
619 n_rxn_env_param, & ! # of rxn env-dependent params
620 n_aero_phase, & ! # of aero phases
621 n_aero_phase_int_param, & ! # of aero phase int params
622 n_aero_phase_float_param, & ! # of aero phase real params
623 n_aero_rep, & ! # of aero reps
624 n_aero_rep_int_param, & ! # of aero rep int params
625 n_aero_rep_float_param, & ! # of aero rep real params
626 n_aero_rep_env_param, & ! # of aero rep env params
627 n_sub_model, & ! # of sub models
628 n_sub_model_int_param, & ! # of sub model int params
629 n_sub_model_float_param, & ! # of sub model real params
630 n_sub_model_env_param & ! # of sub model env params
631 )
632
633 ! Add all the condensed reaction data to the solver data block for
634 ! reactions of the specified phase
635 do i_mech=1, size(mechanisms)
636 do i_rxn=1, mechanisms(i_mech)%val%size()
637
638 ! FIXME Put ZSR aerosol water first, so water is available for other
639 ! reactions - and find a better way to account for inter-dependence
640 ! of reactions/sub-models
641
642 ! Assign rxn to the current reaction
643 rxn => mechanisms(i_mech)%val%get_rxn(i_rxn)
644
645 ! Check reaction phase
646 select case (rxn%rxn_phase)
647 case (gas_rxn)
648 if (rxn_phase.eq.aero_rxn) cycle
649 case (aero_rxn)
650 if (rxn_phase.eq.gas_rxn) cycle
651 case (gas_aero_rxn)
652 if (rxn_phase.eq.gas_rxn) cycle
653 end select
654
655 ! Load temporary data arrays
656 allocate(int_param(size(rxn%condensed_data_int)))
657 allocate(float_param(size(rxn%condensed_data_real)))
658 int_param(:) = int(rxn%condensed_data_int(:), kind=c_int)
659 float_param(:) = real(rxn%condensed_data_real(:), kind=c_double)
660
661 ! Send the condensed data to the solver
663 int(rxn_factory%get_type(rxn), kind=c_int),& ! Rxn type
664 int(size(int_param), kind=c_int), & ! Int array size
665 int(size(float_param), kind=c_int), & ! Real array size
666 rxn%num_env_params, & ! Env-dep array size
667 c_loc(int_param), & ! Int array ptr
668 c_loc(float_param), & ! Real array ptr
669 this%solver_c_ptr & ! Solver data ptr
670 )
671
672 ! Deallocate temporary arrays
673 deallocate(int_param)
674 deallocate(float_param)
675
676 end do
677 end do
678 rxn => null()
679
680 ! Add all the condensed aerosol phase data to the solver data block
681 do i_aero_phase=1, size(aero_phases)
682
683 ! Assign aero_phase to the current aerosol phase
684 aero_phase => aero_phases(i_aero_phase)%val
685
686 ! Load temporary data arrays
687 allocate(int_param(size(aero_phase%condensed_data_int)))
688 allocate(float_param(size(aero_phase%condensed_data_real)))
689 int_param(:) = int(aero_phase%condensed_data_int(:), kind=c_int)
690 float_param(:) = real(aero_phase%condensed_data_real(:), kind=c_double)
691
692 ! Send the condensed data to the solver
694 int(size(int_param), kind=c_int), & ! Int array size
695 int(size(float_param), kind=c_int), & ! Real array size
696 c_loc(int_param), & ! Int array ptr
697 c_loc(float_param), & ! Real array ptr
698 this%solver_c_ptr & ! Solver data ptr
699 )
700
701 ! Deallocate temporary arrays
702 deallocate(int_param)
703 deallocate(float_param)
704
705 end do
706 aero_phase => null()
707
708 ! Add all the condensed aerosol representation data to the solver data
709 ! block
710 do i_aero_rep=1, size(aero_reps)
711
712 ! Assign aero_rep to the current aerosol representation
713 aero_rep => aero_reps(i_aero_rep)%val
714
715 ! Load temporary data arrays
716 allocate(int_param(size(aero_rep%condensed_data_int)))
717 allocate(float_param(size(aero_rep%condensed_data_real)))
718 int_param(:) = int(aero_rep%condensed_data_int(:), kind=c_int)
719 float_param(:) = real(aero_rep%condensed_data_real(:), kind=c_double)
720
721 ! Send the condensed data to the solver
723 int(aero_rep_factory%get_type(aero_rep), kind=c_int), &
724 ! Aero rep type
725 int(size(int_param), kind=c_int), & ! Int array size
726 int(size(float_param), kind=c_int), & ! Real array size
727 aero_rep%num_env_params, & ! Env-dep array size
728 c_loc(int_param), & ! Int array ptr
729 c_loc(float_param), & ! Real array ptr
730 this%solver_c_ptr & ! Solver data ptr
731 )
732
733 ! Deallocate temporary arrays
734 deallocate(int_param)
735 deallocate(float_param)
736
737 end do
738 aero_rep => null()
739
740 ! Add all the condensed sub model data to the solver data block
741 do i_sub_model=1, size(sub_models)
742
743 ! Assign sub_model to the current sub model
744 sub_model => sub_models(i_sub_model)%val
745
746 ! Load temporary data arrays
747 allocate(int_param(size(sub_model%condensed_data_int)))
748 allocate(float_param(size(sub_model%condensed_data_real)))
749 int_param(:) = int(sub_model%condensed_data_int(:), kind=c_int)
750 float_param(:) = real(sub_model%condensed_data_real(:), kind=c_double)
751
752 ! Send the condensed data to the solver
754 int(sub_model_factory%get_type(sub_model), kind=c_int), &
755 ! Sub model type
756 int(size(int_param), kind=c_int), & ! Int array size
757 int(size(float_param), kind=c_int), & ! Real array size
758 sub_model%num_env_params, & ! Env-dep array size
759 c_loc(int_param), & ! Int array ptr
760 c_loc(float_param), & ! Real array ptr
761 this%solver_c_ptr & ! Solver data ptr
762 )
763
764 ! Deallocate temporary arrays
765 deallocate(int_param)
766 deallocate(float_param)
767
768 end do
769 sub_model => null()
770
771 ! Initialize the solver
772 call solver_initialize( &
773 this%solver_c_ptr, & ! Pointer to solver data
774 c_loc(abs_tol_c), & ! Absolute tolerances
775 real(this%rel_tol, kind=c_double), & ! Relative tolerance
776 int(this%max_steps, kind=c_int), & ! Max # of integration steps
777 int(this%max_conv_fails, kind=c_int)& ! Max # of convergence fails
778 )
779
780 ! Flag the solver as initialized
781 this%initialized = .true.
782
783 ! Free memory allocated for solver initialization
784 deallocate(abs_tol_c)
785 deallocate(var_type_c)
786
787 end subroutine initialize
788
789!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
790
791 !> Update sub-model data
792 subroutine update_sub_model_data(this, update_data)
793
794 !> Solver data
795 class(camp_solver_data_t), intent(inout) :: this
796 !> Update data
797 class(sub_model_update_data_t), intent(in) :: update_data
798
800 update_data%get_cell_id()-1, & ! Grid cell to update
801 update_data%sub_model_solver_id, & ! Solver's sub model id
802 update_data%get_type(), & ! Sub-model type to update
803 update_data%get_data(), & ! Data needed to perform update
804 this%solver_c_ptr & ! Pointer to solver data
805 )
806
807 end subroutine update_sub_model_data
808
809!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
810
811 !> Update reaction data
812 subroutine update_rxn_data(this, update_data)
813
814 !> Solver data
815 class(camp_solver_data_t), intent(inout) :: this
816 !> Update data
817 class(rxn_update_data_t), intent(in) :: update_data
818
819 call rxn_update_data( &
820 update_data%get_cell_id()-1, & ! Grid cell to update
821 update_data%rxn_solver_id, & ! Solver's reaction id
822 update_data%get_type(), & ! Reaction type to update
823 update_data%get_data(), & ! Data needed to perform update
824 this%solver_c_ptr & ! Pointer to solver data
825 )
826
827 end subroutine update_rxn_data
828
829!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
830
831 !> Update aerosol representation data based on data passed from the host
832 !! model related to aerosol properties
833 subroutine update_aero_rep_data(this, update_data)
834
835 !> Solver data
836 class(camp_solver_data_t), intent(inout) :: this
837 !> Update data
838 class(aero_rep_update_data_t), intent(in) :: update_data
839
841 update_data%get_cell_id()-1, & ! Grid cell to update
842 update_data%aero_rep_solver_id, & ! Solver's aero rep id
843 update_data%get_type(), & ! Aerosol representation type
844 update_data%get_data(), & ! Data needed to perform update
845 this%solver_c_ptr & ! Pointer to solver data
846 )
847
848 end subroutine update_aero_rep_data
849
850!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
851
852 !> Solve the mechanism(s) for a specified timestep
853 subroutine solve(this, camp_state, t_initial, t_final, solver_stats)
854
855 !> Solver data
856 class(camp_solver_data_t), intent(inout) :: this
857 !> Model state
858 type(camp_state_t), target, intent(inout) :: camp_state
859 !> Start time (s)
860 real(kind=dp), intent(in) :: t_initial
861 !> End time (s)
862 real(kind=dp), intent(in) :: t_final
863 !> Solver statistics
864 type(solver_stats_t), intent(inout), optional, target :: solver_stats
865
866 integer(kind=c_int) :: solver_status
867
868#ifdef CAMP_DEBUG
869 if (present(solver_stats)) then
870 ! Update the debugging output flag in the solver data
871 if (solver_stats%debug_out) then
872 solver_status = solver_set_debug_out( &
873 this%solver_c_ptr, & ! Pointer to the solver data
874 int(1, kind=c_int) & ! Debug flag
875 )
876 else
877 solver_status = solver_set_debug_out( &
878 this%solver_c_ptr, & ! Pointer to the solver data
879 int(0, kind=c_int) & ! Debug flag
880 )
881 end if
882 ! Update Jacobian evaluation flag in the solver data
883 if (solver_stats%eval_Jac) then
884 solver_stats = solver_set_eval_jac( &
885 this%solver_c_ptr, & ! Pointer to the solver data
886 int(1, kind=c_int) & ! Jac eval flag
887 )
888 else
889 solver_stats = solver_set_eval_jac( &
890 this%solver_c_ptr, & ! Pointer to the solver data
891 int(0, kind=c_int) & ! Jac eval flag
892 )
893 end if
894 end if
895
896 ! Reset the solver function timers
897 call this%reset_timers( )
898#endif
899
900 ! Run the solver
901 solver_status = solver_run( &
902 this%solver_c_ptr, & ! Pointer to intialized solver
903 c_loc(camp_state%state_var), & ! Pointer to state array
904 c_loc(camp_state%env_var), & ! Pointer to environmental vars
905 real(t_initial, kind=c_double), & ! Start time (s)
906 real(t_final, kind=c_double) & ! Final time (s)
907 )
908
909 ! Get the solver statistics
910 if (present(solver_stats)) then
911 call this%get_solver_stats( solver_stats )
912 solver_stats%status_code = solver_status
913 solver_stats%start_time__s = t_initial
914 solver_stats%end_time__s = t_final
915 else
916 call warn_assert_msg(997420005, solver_status.eq.0, "Solver failed")
917 end if
918
919 end subroutine solve
920
921!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
922
923 !> Reset the solver function timers
924 subroutine reset_timers( this )
925
926 !> Solver data
927 class(camp_solver_data_t), intent(inout) :: this
928
929 call solver_reset_timers( this%solver_c_ptr )
930
931 end subroutine reset_timers
932
933!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
934
935 !> Get solver statistics
936 subroutine get_solver_stats( this, solver_stats )
937
938 !> Solver data
939 class(camp_solver_data_t), intent(inout) :: this
940 !> Solver statistics
941 type(solver_stats_t), intent(inout), target :: solver_stats
942
944 this%solver_c_ptr, & ! Solver data
945 c_loc( solver_stats%solver_flag ), & ! Last flag returned CVode
946 c_loc( solver_stats%num_steps ), & ! Number of steps
947 c_loc( solver_stats%RHS_evals ), & ! Right-hand side evals
948 c_loc( solver_stats%LS_setups ), & ! Linear solver setups
949 c_loc( solver_stats%error_test_fails ), & ! Error test failures
950 c_loc( solver_stats%NLS_iters ), & ! Non-Linear solver interations
951 c_loc( solver_stats%NLS_convergence_fails ), & ! Non-Linear solver fails
952 c_loc( solver_stats%DLS_Jac_evals ), & ! Jacobian evals
953 c_loc( solver_stats%DLS_RHS_evals ), & ! DLS Right-hand side evals
954 c_loc( solver_stats%last_time_step__s ), & ! Last time step [s]
955 c_loc( solver_stats%next_time_step__s ), & ! Next time step [s]
956 c_loc( solver_stats%Jac_eval_fails ), & ! Number of Jac eval fails
957 c_loc( solver_stats%RHS_evals_total ), & ! total f() calls
958 c_loc( solver_stats%Jac_evals_total ), & ! total Jac() calls
959 c_loc( solver_stats%RHS_time__s ), & ! Compute time f() [s]
960 c_loc( solver_stats%Jac_time__s ), & ! Compute time Jac() [s]
961 c_loc( solver_stats%max_loss_precision ) ) ! Maximum loss of precision
962
963 end subroutine get_solver_stats
964
965!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
966
967 !> Check whether a solver is available for the integration
968 logical function is_solver_available(this)
969
970 !> Solver data
971 class(camp_solver_data_t), intent(in) :: this
972
973#ifdef CAMP_USE_SUNDIALS
974 is_solver_available = .true.
975#else
976 is_solver_available = .false.
977#endif
978
979 end function is_solver_available
980
981!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
982
983 !> Print the solver data
984 subroutine do_print(this)
985
986 !> Solver data
987 class(camp_solver_data_t), intent(in) :: this
988
989 call rxn_print_data(this%solver_c_ptr)
990 call aero_phase_print_data(this%solver_c_ptr)
991 call aero_rep_print_data(this%solver_c_ptr)
992 call sub_model_print_data(this%solver_c_ptr)
993
994 end subroutine do_print
995
996!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
997
998 !> Finalize the solver data
999 elemental subroutine finalize(this)
1000
1001 !> Solver data
1002 type(camp_solver_data_t), intent(inout) :: this
1003
1004 if (this%initialized) call solver_free(this%solver_c_ptr)
1005
1006 end subroutine finalize
1007
1008!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1009
1010end module camp_camp_solver_data
Add condensed aerosol phase data to the solver data block.
Add condensed aerosol representation data to the solver data block.
Print the aerosol representation data.
Update aerosol representation data.
Add condensed reaction data to the solver data block.
Free the memory associated with a solver.
Interface to c ODE solver functions.
Reset the solver function timers.
Add condensed sub model data to the solver data block.
Interface for to_string functions.
Definition util.F90:32
The abstract aero_phase_data_t structure and associated subroutines.
The abstract aero_rep_data_t structure and associated subroutines.
The aero_rep_factory_t type and associated subroutines.
The camp_solver_data_t structure and associated subroutines.
subroutine get_solver_stats(this, solver_stats)
Get solver statistics.
subroutine update_rxn_data(this, update_data)
Update reaction data.
subroutine update_sub_model_data(this, update_data)
Update sub-model data.
elemental subroutine finalize(this)
Finalize the solver data.
type(camp_solver_data_t) function, pointer constructor()
Constructor for camp_solver_data_t.
subroutine do_print(this)
Print the solver data.
subroutine reset_timers(this)
Reset the solver function timers.
logical function is_solver_available(this)
Check whether a solver is available for the integration.
subroutine initialize(this, var_type, abs_tol, mechanisms, aero_phases, aero_reps, sub_models, rxn_phase, n_cells)
Initialize the solver.
real(kind=dp), parameter camp_solver_default_rel_tol
Default relative tolerance for integration.
integer, parameter camp_solver_success
Result code indicating successful completion.
integer(kind=i_kind), parameter camp_solver_default_max_conv_fails
Default maximum number of integration convergence failures.
subroutine solve(this, camp_state, t_initial, t_final, solver_stats)
Solve the mechanism(s) for a specified timestep.
subroutine update_aero_rep_data(this, update_data)
Update aerosol representation data based on data passed from the host model related to aerosol proper...
integer(kind=i_kind), parameter camp_solver_default_max_steps
Default max number of integration steps.
The camp_state_t structure and associated subroutines.
Definition camp_state.F90:9
Physical constants.
Definition constants.F90:9
integer, parameter dp
Kind of a double precision real number.
Definition constants.F90:16
integer, parameter i_kind
Kind of an integer.
Definition constants.F90:21
The mechanism_data_t structure and associated subroutines.
The rxn_data_t structure and associated subroutines.
Definition rxn_data.F90:60
The abstract rxn_factory_t structure and associated subroutines.
The solver_stats_t type and associated subroutines.
The abstract sub_model_data_t structure and associated subroutines.
The sub_model_factory_t type and associated subroutines.
Common utility subroutines.
Definition util.F90:9
subroutine die_msg(code, error_msg)
Error immediately.
Definition util.F90:196
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition util.F90:130
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
Definition util.F90:112