POP Interacting with MARBL Requested Forcings¶
POP mirrors the MARBL datatypes for forcing fields and the associated metadata, but expands the metadata class to also manage the source of the data (read from a file, provided by POP, provided by the flux coupler, etc).
In the code below, surface_forcings(:)
is the MARBL data provided through the interface, and surface_forcing_fields(:)
is the copy into the POP datatype.
allocate(surface_forcing_fields(size(surface_forcings)))
do n=1,size(surface_forcing_fields)
marbl_varname = surface_forcings(n)%metadata%varname
units = surface_forcings(n)%metadata%field_units
select case (trim(surface_forcings(n)%metadata%varname))
case ('surface_mask')
mask_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='SURFACE_MASK', id=n)
case ('d13c')
d13c_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='D13C', id=n)
case ('d14c')
d14c_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='D14C', id=n)
case ('d14c_gloavg')
d14c_glo_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='D14C_GLOAVG', id=n)
case ('u10_sqr')
u10sqr_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='U10_SQR', id=n)
case ('sst')
sst_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='SST', id=n)
case ('sss')
sss_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='SSS', id=n)
case ('xco2')
xco2_ind = n
if (trim(atm_co2_opt).eq.'const') then
call surface_forcing_fields(n)%add_forcing_field(field_source='const', &
marbl_varname=marbl_varname, field_units=units, &
field_constant=atm_co2_const, id=n)
else if (trim(atm_co2_opt).eq.'drv_prog') then
call surface_forcing_fields(n)%add_forcing_field(field_source='named_field', &
marbl_varname=marbl_varname, field_units=units, &
named_field='ATM_CO2_PROG', id=n)
else if (trim(atm_co2_opt).eq.'drv_diag') then
call surface_forcing_fields(n)%add_forcing_field(field_source='named_field', &
marbl_varname=marbl_varname, field_units=units, &
named_field='ATM_CO2_DIAG', id=n)
else
write(err_msg, "(A,1X,A)") trim(atm_co2_opt), &
'is not a valid option for atm_co2_opt'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('xco2_alt_co2')
if (trim(atm_alt_co2_opt).eq.'const') then
call surface_forcing_fields(n)%add_forcing_field(field_source='const', &
marbl_varname=marbl_varname, field_units=units, &
field_constant=atm_alt_co2_const, id=n)
else
write(err_msg, "(A,1X,A)") trim(atm_alt_co2_opt), &
'is not a valid option for atm_alt_co2_opt'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('Ice Fraction')
ifrac_ind = n
if (trim(gas_flux_forcing_opt).eq.'drv') then
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='ICE Fraction', id=n)
else if (trim(gas_flux_forcing_opt).eq.'file') then
file_details => fice_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
else
write(err_msg, "(A,1X,A)") trim(gas_flux_forcing_opt), &
'is not a valid option for gas_flux_forcing_opt'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('Atmospheric Pressure')
ap_ind = n
if (trim(gas_flux_forcing_opt).eq.'drv') then
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='AP_FILE_INPUT', id=n)
else if (trim(gas_flux_forcing_opt).eq.'file') then
file_details => ap_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
else
write(err_msg, "(A,1X,A)") trim(gas_flux_forcing_opt), &
'is not a valid option for gas_flux_forcing_opt'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('Dust Flux')
dust_ind = n
if (trim(dust_flux_source).eq.'driver') then
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='DUST_FLUX', id=n)
else if (trim(dust_flux_source).eq.'monthly-calendar') then
file_details => dust_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
else
write(err_msg, "(A,1X,A)") trim(dust_flux_source), &
'is not a valid option for dust_flux_source'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('Iron Flux')
if (trim(iron_flux_source).eq.'driver-derived') then
bc_ind = n
call surface_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='BLACK_CARBON_FLUX', id=n)
else if (trim(iron_flux_source).eq.'monthly-calendar') then
Fe_ind = n
file_details => iron_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
else
write(err_msg, "(A,1X,A)") trim(iron_flux_source), &
'is not a valid option for iron_flux_source'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('NOx Flux')
nox_ind = n
if (trim(ndep_data_type).eq.'shr_stream') then
call surface_forcing_fields(n)%add_forcing_field(field_source='shr_stream', &
marbl_varname=marbl_varname, field_units=units, &
unit_conv_factor=ndep_shr_stream_scale_factor, &
file_varname='NOy_deposition', &
year_first = ndep_shr_stream_year_first, &
year_last = ndep_shr_stream_year_last, &
year_align = ndep_shr_stream_year_align, &
filename = ndep_shr_stream_file, id=n)
else if (trim(ndep_data_type).eq.'monthly-calendar') then
file_details => nox_flux_monthly_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
else
write(err_msg, "(A,1X,A)") trim(ndep_data_type), &
'is not a valid option for ndep_data_type'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('NHy Flux')
nhy_ind = n
if (trim(ndep_data_type).eq.'shr_stream') then
call surface_forcing_fields(n)%add_forcing_field(field_source='shr_stream', &
marbl_varname=marbl_varname, field_units=units, &
unit_conv_factor=ndep_shr_stream_scale_factor, &
file_varname='NHx_deposition', &
year_first = ndep_shr_stream_year_first, &
year_last = ndep_shr_stream_year_last, &
year_align = ndep_shr_stream_year_align, &
filename = ndep_shr_stream_file, id=n)
else if (trim(ndep_data_type).eq.'monthly-calendar') then
file_details => nhy_flux_monthly_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
else
write(err_msg, "(A,1X,A)") trim(ndep_data_type), &
'is not a valid option for ndep_data_type'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
case ('DIN River Flux')
file_details => din_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DIP River Flux')
file_details => dip_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DON River Flux')
file_details => don_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DOP River Flux')
file_details => dop_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DSi River Flux')
file_details => dsi_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DFe River Flux')
file_details => dfe_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DIC River Flux')
file_details => dic_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('ALK River Flux')
file_details => alk_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case ('DOC River Flux')
file_details => doc_riv_flux_file_loc
call init_monthly_surface_forcing_metadata(file_details)
call surface_forcing_fields(n)%add_forcing_field( &
field_source='POP monthly calendar', &
marbl_varname=marbl_varname, field_units=units, &
forcing_calendar_name=file_details, id=n)
case DEFAULT
write(err_msg, "(A,1X,A)") trim(surface_forcings(n)%metadata%varname), &
'is not a valid surface forcing field name.'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end select
! All surface forcing fields are 0d; if a 1d field is introduced later,
! move this allocate into the select case
allocate(surface_forcing_fields(n)%field_0d(nx_block, ny_block, nblocks_clinic))
! Zero out forcing field. If a 1d field is introduced later, check to see
! which of field_0d and field_1d is allocated.
surface_forcing_fields(n)%field_0d = c0
end do
Note that POP uses field_source
to denote where it will be getting the forcing field.
Not shown in this example is where POP actually populates the data.
The code for interior forcing fields looks similar, although there are far fewer fields to handle and that results in a shorter code snippet.
Again, interior_forcings
is provided through the MARBL interface and interior_forcing_fields
is a POP construct.
allocate(interior_forcing_fields(size(interior_forcings)))
do n=1,size(interior_forcing_fields)
marbl_varname = interior_forcings(n)%metadata%varname
units = interior_forcings(n)%metadata%field_units
var_processed = .false.
! Check to see if this forcing field is tracer restoring
if (index(marbl_varname,'Restoring Field').gt.0) then
tracer_name = trim(marbl_varname(1:scan(marbl_varname,' ')))
do m=1,marbl_tracer_cnt
if (trim(tracer_name).eq.trim(restoreable_tracer_names(m))) then
! Check to make sure restore_data_filenames and
! restore_data_file_varnames have both been provided by namelist
if (len_trim(restore_data_filenames(m)).eq.0) then
write(err_msg, "(3A)") "No file provided to read restoring ", &
"field for ", trim(tracer_name)
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
if (len_trim(restore_data_file_varnames(m)).eq.0) then
write(err_msg, "(3A)") "No variable name provided to read ", &
"restoring field for ", trim(tracer_name)
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end if
if (my_task.eq.master_task) then
write(stdout, "(6A)") "Will restore ", trim(tracer_name), &
" with ", trim(restore_data_file_varnames(m)), &
" from ", trim(restore_data_filenames(m))
end if
call interior_forcing_fields(n)%add_forcing_field( &
field_source='file_time_invariant', &
marbl_varname=marbl_varname, field_units=units, &
filename=restore_data_filenames(m), &
file_varname=restore_data_file_varnames(m), &
id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, km, nblocks_clinic))
var_processed = .true.
exit
end if
end do
end if
! Check to see if this forcing field is a restoring time scale
if (index(marbl_varname,'Restoring Inverse Timescale').gt.0) then
tracer_name = trim(marbl_varname(1:scan(marbl_varname,' ')))
select case (trim(restore_inv_tau_opt))
case('const')
call interior_forcing_fields(n)%add_forcing_field( &
field_source='const', &
marbl_varname=marbl_varname, field_units=units, &
field_constant = restore_inv_tau_const, &
id=n)
! case('shr_stream')
! NOT SUPPORTED YET
! will require additional namelist variables, and we can consider
! reading in one file per tracer instead of using the same mask
! for all restoring fields
case DEFAULT
write(err_msg, "(A,1X,A)") trim(restore_inv_tau_opt), &
'is not a valid option for restore_inv_tau_opt'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end select
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, km, nblocks_clinic))
var_processed = .true.
end if
if (.not.var_processed) then
select case (trim(interior_forcings(n)%metadata%varname))
case ('Dust Flux')
dustflux_ind = n
call interior_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='dust_flux', id=n)
allocate(interior_forcing_fields(n)%field_0d(nx_block, ny_block, nblocks_clinic))
case ('PAR Column Fraction')
PAR_col_frac_ind = n
call interior_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='PAR_col_frac', id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, mcog_nbins, nblocks_clinic))
case ('Surface Shortwave')
surf_shortwave_ind = n
call interior_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='surf_shortwave', id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, mcog_nbins, nblocks_clinic))
case ('Temperature')
temperature_ind = n
call interior_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='temperature', id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, km, nblocks_clinic))
case ('Salinity')
salinity_ind = n
call interior_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='salinity', id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, km, nblocks_clinic))
case ('Pressure')
pressure_ind = n
call interior_forcing_fields(n)%add_forcing_field(field_source='internal', &
marbl_varname=marbl_varname, field_units=units, &
driver_varname='pressure', id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, km, nblocks_clinic))
case ('Iron Sediment Flux')
fesedflux_ind = n
call interior_forcing_fields(n)%add_forcing_field( &
field_source='file_time_invariant', &
marbl_varname=marbl_varname, field_units=units, &
filename=fesedflux_input%filename, &
file_varname=fesedflux_input%file_varname, &
id=n)
allocate(interior_forcing_fields(n)%field_1d(nx_block, ny_block, km, nblocks_clinic))
case DEFAULT
write(err_msg, "(A,1X,A)") trim(interior_forcings(n)%metadata%varname), &
'is not a valid interior forcing field name.'
call document(subname, err_msg)
call exit_POP(sigAbort, 'Stopping in ' // subname)
end select
end if
! Zero out field
if (allocated(interior_forcing_fields(n)%field_0d)) then
interior_forcing_fields(n)%field_0d = c0
else
interior_forcing_fields(n)%field_1d = c0
end if
end do