25 character(len=*),
parameter ::
new_line = char(10)
32 character(len=:),
allocatable :: name
34 integer(kind=i_kind) :: curr_time_step
36 integer(kind=i_kind) :: curr_transition
38 integer(kind=i_kind),
allocatable :: transition_time_step(:)
40 real(kind=dp),
allocatable :: transition_value(:)
55 procedure :: profile_constructor
73 procedure :: rxn_profile_constructor
80 integer(kind=i_kind) :: update_type
82 integer(kind=i_kind) :: section_id = 0
95 procedure :: aero_rep_profile_constructor
111 integer(kind=i_kind) :: num_steps
113 real(kind=dp) :: time_step__s
115 real(kind=dp) :: total_time__s
137 procedure :: constructor
154 character(len=*),
intent(in) :: config_file
156 type(json_core),
target :: json
157 type(json_file) :: j_file
158 type(json_value),
pointer :: j_obj, j_next, j_box_config
160 logical(kind=json_lk) :: found, valid
161 character(kind=json_ck, len=:),
allocatable :: unicode_str_val
162 character(kind=json_ck, len=:),
allocatable :: json_err_msg
163 character(kind=json_ck, len=:),
allocatable ::
spec_name
164 integer(kind=json_ik) :: int_value
165 real(kind=json_rk) :: real_value
167 logical :: file_exists
168 integer(kind=i_kind) :: num_rates, i_rate
169 integer(kind=i_kind) :: num_aero_reps, i_aero_rep
170 integer(kind=i_kind) :: spec_id
177 call new_obj%camp_core%initialize( )
180 new_obj%spec_names = new_obj%camp_core%unique_names( )
183 call j_file%initialize( )
184 call j_file%get_core( json )
186 call assert_msg( 135902099, trim( config_file ).ne.
"", &
187 "Received empty string for file path" )
188 inquire( file = trim( config_file ), exist = file_exists )
189 call assert_msg( 181758805, file_exists,
"Cannot find file: "// &
190 trim( config_file ) )
191 call j_file%load_file( filename = trim( config_file ) )
194 call j_file%get(
"camp-box-model", j_box_config, found )
196 "Missing 'camp-box-model' configuration data "// &
197 "in configuration file.")
198 call json%validate( j_box_config, valid, json_err_msg )
200 "Bad JSON format in 'camp-box-model' configuration "// &
201 "data: "//trim( json_err_msg ) )
204 call json%get_child( j_box_config,
"output time step [s]", j_obj, found )
206 "Missing 'output time step [s]' "// &
207 "in box model data" )
208 call json%get( j_obj, real_value )
209 new_obj%time_step__s = real_value
212 call json%get_child( j_box_config,
"total integration time [s]", j_obj, &
215 "Missing 'total integration time [s]' "// &
216 "in box model data" )
217 call json%get( j_obj, real_value )
218 new_obj%num_steps = ceiling( real_value / new_obj%time_step__s )
219 new_obj%total_time__s = real_value
222 call json%get_child( j_box_config,
"temperature [K]", j_obj, found )
224 "Missing 'temperature [K]' "// &
225 "in box model data" )
226 new_obj%temperature__K =
profile_t( json, j_obj )
229 call json%get_child( j_box_config,
"pressure [Pa]", j_obj, found )
231 "Missing 'pressure [Pa]' "// &
232 "in box model data" )
233 new_obj%pressure__Pa =
profile_t( json, j_obj )
236 call json%get_child( j_box_config,
"rates", j_obj, found )
238 call json%info( j_obj, n_children = num_rates )
239 allocate( new_obj%rxn_profiles( num_rates ) )
241 call json%get( j_box_config,
"rates(1)", j_obj, found )
242 call assert( 693229278, found )
244 do while(
associated( j_obj ) )
246 new_obj%rxn_profiles( i_rate ) = &
248 call json%get_next( j_obj, j_next )
251 call assert( 763815888, i_rate .eq. num_rates)
255 call json%get_child( j_box_config,
"aerosol representations", j_obj, &
258 call json%info( j_obj, n_children = num_aero_reps )
259 allocate( new_obj%aero_rep_profiles( num_aero_reps ) )
261 call json%get( j_box_config,
"aerosol representations(1)", j_obj, &
263 call assert( 877171198, found )
265 do while(
associated( j_obj ) )
266 i_aero_rep = i_aero_rep + 1
267 new_obj%aero_rep_profiles( i_aero_rep ) = &
269 call json%get_next( j_obj, j_next )
272 call assert( 472301285, i_aero_rep .eq. num_aero_reps )
277 call new_obj%camp_core%solver_initialize( )
280 new_obj%camp_state => new_obj%camp_core%new_state( )
281 new_obj%initial_camp_state => new_obj%camp_core%new_state( )
284 call json%get( j_box_config,
"initial state(1)", j_obj, found )
287 do while(
associated( j_obj ) )
288 call json%info( j_obj, name =
spec_name )
289 call json%get( j_obj, real_value )
291 new_obj%camp_core%spec_state_id(
spec_name, &
293 "Cannot find species '"//trim(
spec_name )// &
294 "' in the chemical mechanism" )
295 new_obj%initial_camp_state%state_var( spec_id ) = real_value
296 call json%get_next( j_obj, j_next )
302 call new_obj%initial_camp_state%env_states(1)%set_temperature_K( &
303 new_obj%temperature__K%current_value( ) )
304 call new_obj%initial_camp_state%env_states(1)%set_pressure_Pa( &
305 new_obj%pressure__Pa%current_value( ) )
306 call new_obj%initial_camp_state%update_env_state( )
309 call j_file%destroy( )
314 call die_msg( 444795237,
"JSON must be enabled for the CAMP box model" )
322 subroutine run( this, output_file_unit )
329 integer(kind=i_kind),
intent(in),
optional :: output_file_unit
333 integer(kind=i_kind) :: f_unit
334 integer(kind=i_kind) :: i_time, i_rate
335 real(kind=dp) :: step_size__s, curr_time__s
338 if(
present( output_file_unit ) ) f_unit = output_file_unit
341 this%camp_state%state_var( : ) = this%initial_camp_state%state_var( : )
342 this%camp_state%env_var( : ) = this%initial_camp_state%env_var( : )
345 write(f_unit,*) 0.0, this%camp_state%env_var( : ), &
346 this%camp_state%state_var( : )
349 call this%temperature__K%reset( )
350 call this%pressure__Pa%reset( )
351 do i_rate = 1,
size( this%rxn_profiles )
352 call this%rxn_profiles( i_rate )%reset( )
356 do i_time = 1, this%num_steps
359 curr_time__s = i_time * this%time_step__s
360 if( curr_time__s .gt. this%total_time__s )
then
361 step_size__s = this%time_step__s - &
362 (curr_time__s - this%total_time__s )
364 step_size__s = this%time_step__s
368 call this%temperature__K%advance( )
369 call this%camp_state%env_states(1)%set_temperature_K( &
370 this%temperature__K%current_value( ) )
371 call this%pressure__Pa%advance( )
372 call this%camp_state%env_states(1)%set_pressure_Pa( &
373 this%pressure__Pa%current_value( ) )
374 do i_rate = 1,
size( this%rxn_profiles )
375 call this%rxn_profiles( i_rate )%advance( )
376 call this%rxn_profiles( i_rate )%update_rxn( this%camp_core )
380 call this%camp_core%solve( this%camp_state, step_size__s, &
381 solver_stats = solver_stats )
384 write(f_unit,*) curr_time__s, this%camp_state%env_var( : ), &
385 this%camp_state%state_var( : )
400 character(len=*),
intent(in) :: file_prefix
402 character(len=:),
allocatable ::
spec_name, file_name
403 integer(kind=i_kind) :: f_unit, i_char, i_spec
408 file_name = file_prefix//
".conf"
409 open(unit=f_unit, file=file_name, status=
"replace", action=
"write")
410 write(f_unit,*)
"# GNU Plot configuration for CAMP box model output"
411 write(f_unit,*)
"# Run as: gnuplot "//file_name
412 write(f_unit,*)
"set terminal png truecolor"
413 write(f_unit,*)
"set autoscale"
414 write(f_unit,*)
"set xrange [ 0.0:", this%total_time__s,
"]"
417 write(f_unit,*)
"set output '"//file_prefix//
"_temperature.png"
418 write(f_unit,*)
"plot\"
419 write(f_unit,*)
" '"//file_prefix//
"_results.txt'\"
420 write(f_unit,*)
" using 1:2 title 'Temperature [K]'"
421 write(f_unit,*)
"set output '"//file_prefix//
"_pressure.png"
422 write(f_unit,*)
"plot\"
423 write(f_unit,*)
" '"//file_prefix//
"_results.txt'\"
424 write(f_unit,*)
" using 1:3 title 'Pressure [Pa]'"
427 do i_spec = 1,
size( this%spec_names )
428 spec_name = this%spec_names( i_spec )%string
432 write(f_unit,*)
"set output '"//file_prefix//
"_"//
spec_name//
".png'"
433 write(f_unit,*)
"plot\"
434 write(f_unit,*)
" '"//file_prefix//
"_results.txt'\"
435 write(f_unit,*)
" using 1:"//trim(
to_string( i_spec + 3 ) )// &
441 deallocate( file_name )
453 integer(kind=i_kind),
intent(in),
optional :: file_unit
455 character(len=*),
parameter :: fmt_blank_line =
"('')"
456 character(len=*),
parameter :: fmt_state_hdr = &
457 "(' | ',A50,' | ',A13,' |')"
458 character(len=*),
parameter :: fmt_state_data = &
459 "(' | ',A50,' | ',ES13.3,' |')"
460 integer(kind=i_kind) :: f_unit, i_rate, i_spec
463 if(
present( file_unit ) ) f_unit = file_unit
465 write(f_unit,*)
"**********************"
466 write(f_unit,*)
"*** CAMP Box Model ***"
467 write(f_unit,*)
"**********************"
468 write(f_unit,fmt_blank_line)
469 write(f_unit,*)
"total integration time", this%total_time__s,
"s"
470 write(f_unit,*)
"time step size ", this%time_step__s,
"s"
471 write(f_unit,*)
"number of time steps ", this%num_steps
472 write(f_unit,fmt_blank_line)
473 write(f_unit,*)
"** temperature profile **"
474 call this%temperature__K%print( f_unit )
475 write(f_unit,*)
"** end temperature profile **"
476 write(f_unit,fmt_blank_line)
477 write(f_unit,*)
"** pressure [Pa] profile **"
478 call this%pressure__Pa%print( f_unit )
479 write(f_unit,*)
"** end pressure [Pa] profile **"
480 write(f_unit,fmt_blank_line)
481 write(f_unit,*)
"****************************"
482 write(f_unit,*)
"** Reaction Rate Profiles **"
483 write(f_unit,*)
"****************************"
484 write(f_unit,fmt_blank_line)
485 do i_rate = 1,
size( this%rxn_profiles )
486 call this%rxn_profiles( i_rate )%print( f_unit )
487 write(f_unit,fmt_blank_line)
489 write(f_unit,*)
"****************************"
490 write(f_unit,*)
"** Reaction Rate Profiles **"
491 write(f_unit,*)
"****************************"
492 write(f_unit,fmt_blank_line)
493 write(f_unit,*)
"*******************"
494 write(f_unit,*)
"** Initial State **"
495 write(f_unit,*)
"*******************"
496 write(f_unit,fmt_blank_line)
497 write(f_unit,fmt_state_hdr)
"Species",
"Value"
498 do i_spec = 1,
size( this%spec_names )
499 write(f_unit,fmt_state_data) this%spec_names( i_spec )%string, &
500 this%initial_camp_state%state_var( i_spec )
502 write(f_unit,fmt_blank_line)
503 call this%camp_core%print( f_unit )
504 write(f_unit,fmt_blank_line)
505 write(f_unit,*)
"***********************"
506 write(f_unit,*)
"** End Initial State **"
507 write(f_unit,*)
"***********************"
508 write(f_unit,fmt_blank_line)
509 write(f_unit,*)
"**************************"
510 write(f_unit,*)
"*** End CAMP Box Model ***"
511 write(f_unit,*)
"**************************"
523 if(
associated( this%camp_core ) ) &
524 deallocate( this%camp_core )
525 if(
associated( this%camp_state ) ) &
526 deallocate( this%camp_state )
527 if(
associated( this%initial_camp_state) ) &
528 deallocate( this%initial_camp_state )
529 if(
allocated( this%spec_names ) ) &
530 deallocate( this%spec_names )
531 if(
allocated( this%rxn_profiles ) ) &
532 deallocate( this%rxn_profiles )
533 if(
allocated( this%aero_rep_profiles ) ) &
534 deallocate( this%aero_rep_profiles )
549 type(json_core),
intent(inout) :: json
551 type(json_value),
pointer,
intent(inout) :: j_obj
553 type(json_value),
pointer :: j_child, j_next, j_val
554 integer(kind=json_ik) :: num_trans
555 logical(kind=json_lk) :: found
556 character(kind=json_ck, len=:),
allocatable :: profile_name
558 integer(kind=i_kind) :: i_trans
561 call json%info( j_obj, name = profile_name )
562 new_obj%name = profile_name
565 call json%get_child( j_obj,
"transitions", j_child, found )
567 call json%info( j_obj, n_children = num_trans )
568 allocate( new_obj%transition_time_step( 0:num_trans ) )
569 allocate( new_obj%transition_value( 0:num_trans ) )
571 call json%get( j_obj,
"transitions(1)", j_child, found )
573 do while(
associated( j_child ) )
574 i_trans = i_trans + 1
577 call json%get_child( j_child,
"time step", j_val, found )
579 "Missing 'time step' from element "// &
580 trim(
to_string( i_trans ) )//
" in transition '"// &
581 trim( new_obj%name )//
"'" )
582 call json%get( j_val, new_obj%transition_time_step( i_trans ) )
585 call json%get_child( j_child,
"value", j_val, found )
587 "Missing 'value' from element "// &
588 trim(
to_string( i_trans ) )//
" in transition '"// &
589 trim( new_obj%name )//
"'" )
590 call json%get( j_val, new_obj%transition_value( i_trans ) )
591 call json%get_next( j_child, j_next )
594 call assert( 249923619, i_trans .eq. num_trans )
596 allocate( new_obj%transition_time_step( 0:0 ) )
597 allocate( new_obj%transition_value( 0:0 ) )
601 call json%get_child( j_obj,
"initial", j_val, found )
603 "Missing 'initial' value in profile '"// &
604 trim( new_obj%name )//
"'" )
605 call json%get( j_val, new_obj%transition_value( 0 ) )
606 new_obj%transition_time_step( 0 ) = 1
608 call new_obj%reset( )
620 this%curr_transition = 0
621 this%curr_time_step = 1
633 this%curr_time_step = this%curr_time_step + 1
635 if( this%curr_transition .eq. &
636 size( this%transition_time_step ) - 1 )
return
638 if( this%transition_time_step( this%curr_transition + 1 ) .eq. &
639 this%curr_time_step ) &
640 this%curr_transition = this%curr_transition + 1
654 current_value = this%transition_value( this%curr_transition )
666 integer(kind=i_kind),
intent(in),
optional :: file_unit
668 character(len=*),
parameter :: fmt_trans_hdr = &
669 "(' | ',A13,' | ',A13,' |')"
670 character(len=*),
parameter :: fmt_trans_data = &
671 "(' | ',I13,' | ',ES13.3,' |')"
672 integer(kind=i_kind) :: f_unit, i_trans
675 if(
present( file_unit ) ) f_unit = file_unit
677 write(f_unit,*)
"Profile name: "//trim(this%name)
678 write(f_unit,*)
" ** Transitions **"
679 write(f_unit,fmt_trans_hdr)
"Time Step",
"Value"
680 do i_trans = 0,
size( this%transition_time_step ) - 1
681 write(f_unit,fmt_trans_data) this%transition_time_step( i_trans ), &
682 this%transition_value( i_trans )
684 write(f_unit,*)
" ** End Transitions **"
705 type(json_core),
intent(inout) :: json
707 type(json_value),
pointer,
intent(inout) :: j_obj
713 integer(kind=i_kind) :: i_mech, i_rxn
714 character(len=:),
allocatable :: rxn_label
721 new_obj%name = base_profile%name
722 new_obj%transition_time_step = base_profile%transition_time_step
723 new_obj%transition_value = base_profile%transition_value
726 do i_mech = 1,
size( camp_core%mechanism )
727 mech => camp_core%mechanism( i_mech )%val
728 do i_rxn = 1, mech%size( )
729 rxn => mech%get_rxn( i_rxn )
730 if( .not. rxn%property_set%get_string(
"camp-box-model-id", &
732 if( .not. trim( rxn_label ) .eq. new_obj%name ) cycle
743 call die_msg( 592455681,
"Invalid reaction for rate updates" )
745 call camp_core%initialize_update_object( rxn, new_obj%update_data )
752 call assert_msg( 800298506, found,
"Could not find reaction label '"// &
753 trim( new_obj%name ) )
774 select type( ud => this%update_data )
776 call ud%set_rate( this%current_value( ) )
778 call ud%set_rate( this%current_value( ) )
780 call ud%set_rate( this%current_value( ) )
782 call ud%set_rate( this%current_value( ) )
784 call die( 497670619 )
787 call camp_core%update_data( this%update_data )
799 if(
associated( this%update_data ) )
deallocate( this%update_data )
819 type(json_core),
intent(inout) :: json
821 type(json_value),
pointer,
intent(inout) :: j_obj
826 character(kind=json_ck, len=:),
allocatable :: update_type
827 character(kind=json_ck, len=:),
allocatable :: section_name
828 logical(kind=json_lk) :: found
830 integer(kind=i_kind) :: i_aero_rep
831 character(len=:),
allocatable :: aero_rep_label
837 new_obj%name = base_profile%name
838 new_obj%transition_time_step = base_profile%transition_time_step
839 new_obj%transition_value = base_profile%transition_value
842 call json%get( j_obj,
"update type", update_type, found )
844 "Missing update type for aerosol representation "// &
845 "profile '"//new_obj%name//
"'" )
848 do i_aero_rep = 1,
size( camp_core%aero_rep )
849 aero_rep => camp_core%aero_rep( i_aero_rep )%val
850 if( .not. aero_rep%property_set%get_string(
"camp-box-model-id", &
851 aero_rep_label ) ) cycle
852 if( .not. trim( aero_rep_label ) .eq. new_obj%name ) cycle
853 select type( aero_rep )
857 call json%get( j_obj,
"section name", section_name, found )
859 "Missing section name for modal/binned "// &
860 "aerosol representation '"//new_obj%name//
"'" )
861 call assert_msg( 112599854, aero_rep%get_section_id( section_name, &
862 new_obj%section_id ), &
863 "Cannot find aerosol section '"//section_name// &
864 "' in aerosol representation '"// &
866 select case( update_type )
872 call die_msg( 513320382,
"Invalid update type for "// &
873 "modal/binned aerosol rep: "//update_type )
876 select case( update_type )
877 case(
"UPDATE_NUMBER" )
880 call die_msg( 379396160,
"Invalid update type for "// &
881 "single particle aerosol rep: "//update_type )
884 call die_msg( 203974949,
"Invalid aerosol representation " )
886 call camp_core%initialize_update_object( aero_rep, new_obj%update_data )
891 call assert_msg( 712992422, found,
"Could not find aerosol "// &
892 "representation label '"// trim( new_obj%name ) )
911 select type( ud => this%update_data )
913 call assert( 832366630, this%section_id.gt.0 )
914 call ud%set_GMD( this%section_id, this%current_value( ) )
916 call assert( 264057359, this%section_id.gt.0 )
917 call ud%set_GSD( this%section_id, this%current_value( ) )
919 call ud%set_number__n_m3( 1, this%current_value( ) )
921 call die( 623019372 )
924 call camp_core%update_data( this%update_data )
936 if(
associated( this%update_data ) )
deallocate( this%update_data )
Get the non-unique name of a chemical species by its unique name.
Interface for to_string functions.
The abstract aero_rep_data_t structure and associated subroutines.
subroutine do_print(this, file_unit)
Print the aerosol representation data.
The abstract aero_rep_modal_binned_mass_t structure and associated subroutines.
The aero_rep_single_particle_t type and associated subroutines.
A simple box model for CAMP mechanisms.
subroutine rxn_profile_finalize(this)
Finalize the reaction profile.
subroutine profile_do_print(this, file_unit)
Print the profile configuration.
type(camp_box_model_data_t) function, pointer constructor(config_file)
Constructor for the CAMP box model.
character(len= *), parameter new_line
integer(kind=i_kind), parameter scripts_file_unit
subroutine finalize(this)
Finalize the box model.
subroutine update_rxn(this, camp_core)
Update a reaction with the current rate from the profile.
subroutine advance(this)
Advance the profile by one time step.
type(aero_rep_profile_t) function aero_rep_profile_constructor(camp_core, json, j_obj)
Constructor for aero_rep_profile_t.
type(rxn_profile_t) function rxn_profile_constructor(camp_core, json, j_obj)
Constructor for rxn_profile_t.
subroutine reset(this)
Reset the profile to the initial state.
real(kind=dp) function current_value(this)
Get the current value of the profile.
subroutine create_gnuplot_config_file(this, file_prefix)
Create a gnuplot configuration file for plotting box model results.
subroutine run(this, output_file_unit)
Run the camp-chem box model.
subroutine aero_rep_profile_finalize(this)
Finalize the aerosol representation profile.
type(profile_t) function profile_constructor(json, j_obj)
Constructor for profile_t.
subroutine update_aero_rep(this, camp_core)
Update a reaction with the current rate from the profile.
The camp_core_t structure and associated subroutines.
The camp_state_t structure and associated subroutines.
The mechanism_data_t structure and associated subroutines.
The rxn_data_t structure and associated subroutines.
The rxn_emission_t type and associated functions.
The rxn_first_order_loss_t type and associated functions.
The rxn_photolysis_t type and associated functions.
The rxn_wet_deposition_t type and associated functions.
The solver_stats_t type and associated subroutines.
Common utility subroutines.
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
subroutine die_msg(code, error_msg)
Error immediately.
subroutine die(code)
Error immediately.
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Abstract aerosol representation data type.
Modal mass aerosol representation.
Single particle aerosol representation.
Single particle update number concentration object.
Aerosol representation time profile.
Reaction rate time profile.
Abstract reaction data type.
Generic test reaction data type.
Emission rate update object.
Generic test reaction data type.
First-Order Loss rate update object.
Generic test reaction data type.
Photolysis rate update object.
Wet Deposition rate update object.
Generic test reaction data type.
String type for building arrays of string of various size.