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, marbl_req_surface_flux_forcings(:) is the MARBL data provided through the interface, and surface_flux_forcings(:) is the copy into the POP datatype.

do n=1,size(surface_flux_forcings)
  marbl_varname = marbl_req_surface_flux_forcings(n)%metadata%varname
  units         = marbl_req_surface_flux_forcings(n)%metadata%field_units
  select case (trim(marbl_req_surface_flux_forcings(n)%metadata%varname))
    case ('d13c')
      d13c_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='d13C', rank=2, id=n)

    case ('d14c')
      d14c_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='D14C', rank=2, id=n)

    case ('u10_sqr')
      u10sqr_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='U10_SQR', rank=2, id=n)

    case ('sst')
      sst_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='SST', rank=2, id=n)

    case ('sss')
      sss_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='SSS', rank=2, id=n)

    case ('xco2')
      if (trim(atm_co2_opt).eq.'const') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='const', &
             marbl_varname=marbl_varname, field_units=units,                        &
             field_constant=atm_co2_const, rank=2, id=n)
      else if (trim(atm_co2_opt).eq.'drv_prog') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='named_field', &
             marbl_varname=marbl_varname, field_units=units,                              &
             named_field='ATM_CO2_PROG', rank=2, id=n)
      else if (trim(atm_co2_opt).eq.'drv_diag') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='named_field', &
             marbl_varname=marbl_varname, field_units=units,                              &
             named_field='ATM_CO2_DIAG', rank=2, id=n)
      else if (trim(atm_co2_opt).eq.'box_atm_co2') then
        box_atm_co2_ind = n
        call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
             marbl_varname=marbl_varname, field_units=units,                           &
             driver_varname='box_atm_co2', rank=2, 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_flux_forcings(n)%add_forcing_field(field_source='const', &
             marbl_varname=marbl_varname, field_units=units,                        &
             field_constant=atm_alt_co2_const, rank=2, id=n)
      else if (trim(atm_alt_co2_opt).eq.'box_atm_co2') then
        if (trim(atm_co2_opt).eq.'box_atm_co2') then
          box_atm_co2_dup_ind = n
        else
          box_atm_co2_ind = n
        end if
        call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
             marbl_varname=marbl_varname, field_units=units,                           &
             driver_varname='box_atm_co2', rank=2, 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_flux_forcings(n)%add_forcing_field(field_source='internal', &
             marbl_varname=marbl_varname, field_units=units,                           &
             driver_varname='ICE Fraction', rank=2, id=n)
      else if (trim(gas_flux_forcing_opt).eq.'file') then
        file_details => fice_file_loc
        call init_monthly_surface_flux_forcing_metadata(file_details)
        call surface_flux_forcings(n)%add_forcing_field(                    &
             field_source='POP monthly calendar',                                 &
             marbl_varname=marbl_varname, field_units=units,                      &
             forcing_calendar_name=file_details, rank=2, 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_flux_forcings(n)%add_forcing_field(field_source='internal', &
             marbl_varname=marbl_varname, field_units=units,                           &
             driver_varname='AP_FILE_INPUT', rank=2, id=n)
      else if (trim(gas_flux_forcing_opt).eq.'file') then
        file_details => ap_file_loc
        call init_monthly_surface_flux_forcing_metadata(file_details)
        call surface_flux_forcings(n)%add_forcing_field(                    &
             field_source='POP monthly calendar',                                 &
             marbl_varname=marbl_varname, field_units=units,                      &
                             forcing_calendar_name=file_details, rank=2, 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_dep_ind = n
      if (trim(dust_flux_source).eq.'driver') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
             marbl_varname=marbl_varname, field_units=units,                           &
             driver_varname='DUST_FLUX', rank=2, id=n)
      else if (trim(dust_flux_source).eq.'monthly-calendar') then
        file_details => dust_flux_file_loc
        call init_monthly_surface_flux_forcing_metadata(file_details)
        call surface_flux_forcings(n)%add_forcing_field(                    &
             field_source='POP monthly calendar',                                 &
             marbl_varname=marbl_varname, field_units=units,                      &
             forcing_calendar_name=file_details, rank=2, 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_dep_ind = n
        call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
             marbl_varname=marbl_varname, field_units=units,                           &
             driver_varname='BLACK_CARBON_FLUX', rank=2, id=n)
      else if (trim(iron_flux_source).eq.'monthly-calendar') then
        Fe_dep_ind = n
        file_details => iron_flux_file_loc
        call init_monthly_surface_flux_forcing_metadata(file_details)
        call surface_flux_forcings(n)%add_forcing_field(                    &
             field_source='POP monthly calendar',                                 &
             marbl_varname=marbl_varname, field_units=units,                      &
             forcing_calendar_name=file_details, rank=2, 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')
      if (trim(ndep_data_type).eq.'shr_stream') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='shr_stream', &
             strdata_inputlist_ptr=surface_strdata_inputlist_ptr,                        &
             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,                                            &
             rank = 2, id = n)
      else if (trim(ndep_data_type).eq.'monthly-calendar') then
        file_details => nox_flux_monthly_file_loc
        call init_monthly_surface_flux_forcing_metadata(file_details)
        call surface_flux_forcings(n)%add_forcing_field(                    &
             field_source='POP monthly calendar',                                 &
             marbl_varname=marbl_varname, field_units=units,                      &
             forcing_calendar_name=file_details, rank=2, id=n)
      else if (trim(ndep_data_type).eq.'driver') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='named_field', &
             marbl_varname=marbl_varname, field_units=units,                              &
             named_field='ATM_NOy', rank=2, 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')
      if (trim(ndep_data_type).eq.'shr_stream') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='shr_stream', &
             strdata_inputlist_ptr=surface_strdata_inputlist_ptr,                        &
             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,                                            &
             rank = 2, id = n)
      else if (trim(ndep_data_type).eq.'monthly-calendar') then
        file_details => nhy_flux_monthly_file_loc
        call init_monthly_surface_flux_forcing_metadata(file_details)
        call surface_flux_forcings(n)%add_forcing_field(                    &
             field_source='POP monthly calendar',                                 &
             marbl_varname=marbl_varname, field_units=units,                      &
             forcing_calendar_name=file_details, rank=2, id=n)
      else if (trim(ndep_data_type).eq.'driver') then
        call surface_flux_forcings(n)%add_forcing_field(field_source='named_field', &
             marbl_varname=marbl_varname, field_units=units,                              &
             named_field='ATM_NHx', rank=2, 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 ('external C Flux')
      ext_C_flux_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='ext_C_flux', rank=2, id=n)

    case ('external P Flux')
      ext_P_flux_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='ext_P_flux', rank=2, id=n)

    case ('external Si Flux')
      ext_Si_flux_ind = n
      call surface_flux_forcings(n)%add_forcing_field(field_source='internal', &
           marbl_varname=marbl_varname, field_units=units,                           &
           driver_varname='ext_Si_flux', rank=2, id=n)

    case DEFAULT
      write(err_msg, "(A,1X,A)") trim(marbl_req_surface_flux_forcings(n)%metadata%varname), &
                     'is not a valid surface flux forcing field name.'
      call document(subname, err_msg)
      call exit_POP(sigAbort, 'Stopping in ' // subname)
  end select
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, marbl_req_interior_tendency_forcings is provided through the MARBL interface and interior_tendency_forcings is a POP construct.

do n=1,size(interior_tendency_forcings)
  marbl_varname = marbl_req_interior_tendency_forcings(n)%metadata%varname
  units = marbl_req_interior_tendency_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(restorable_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_tendency_forcings(n)%add_forcing_field(                &
                   field_source='shr_stream',                             &
                   strdata_inputlist_ptr=interior_strdata_inputlist_ptr,  &
                   marbl_varname=marbl_varname, field_units=units,        &
                   filename=restore_data_filenames(m),                    &
                   file_varname=restore_data_file_varnames(m),            &
                   year_first=restore_year_first(m),                      &
                   year_last=restore_year_last(m),                        &
                   year_align=restore_year_align(m),                      &
                   unit_conv_factor=restore_scale_factor(m),              &
                   rank=3, dim3_len=km, id=n)
        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
    select case (trim(restore_inv_tau_opt))
      case('const')
        call interior_tendency_forcings(n)%add_forcing_field(                &
                   field_source='const',                                  &
                   marbl_varname=marbl_varname, field_units=units,        &
                   field_constant=restore_inv_tau_const,                  &
                   rank=3, dim3_len=km, id=n)
      case('file_time_invariant')
        call interior_tendency_forcings(n)%add_forcing_field(                &
                   field_source='file_time_invariant',                    &
                   marbl_varname=marbl_varname, field_units=units,        &
                   filename=restore_inv_tau_input%filename,               &
                   file_varname=restore_inv_tau_input%file_varname,       &
                   unit_conv_factor=restore_inv_tau_input%scale_factor,   &
                   rank=3, dim3_len=km, id=n)
      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
    var_processed = .true.
  end if

  if (.not.var_processed) then
    select case (trim(marbl_req_interior_tendency_forcings(n)%metadata%varname))
      case ('Dust Flux')
        dustflux_ind = n
        call interior_tendency_forcings(n)%add_forcing_field(field_source='internal', &
                      marbl_varname=marbl_varname, field_units=units,              &
                      driver_varname='dust_flux', rank=2, id=n)
      case ('PAR Column Fraction')
        PAR_col_frac_ind = n
        call interior_tendency_forcings(n)%add_forcing_field(field_source='internal', &
                      marbl_varname=marbl_varname, field_units=units,              &
                      driver_varname='PAR_col_frac', rank=3, dim3_len=mcog_nbins,  &
                      ldim3_is_depth=.false., id=n)
      case ('Surface Shortwave')
        surf_shortwave_ind = n
        call interior_tendency_forcings(n)%add_forcing_field(field_source='internal',  &
                      marbl_varname=marbl_varname, field_units=units,               &
                      driver_varname='surf_shortwave', rank=3, dim3_len=mcog_nbins, &
                      ldim3_is_depth=.false., id=n)
      case ('Potential Temperature')
        potemp_ind = n
        call interior_tendency_forcings(n)%add_forcing_field(field_source='internal', &
                      marbl_varname=marbl_varname, field_units=units,              &
                      driver_varname='temperature', rank=3, dim3_len=km, id=n)
      case ('Salinity')
        salinity_ind = n
        call interior_tendency_forcings(n)%add_forcing_field(field_source='internal', &
                      marbl_varname=marbl_varname, field_units=units,              &
                      driver_varname='salinity', rank=3, dim3_len=km, id=n)
      case ('Pressure')
        pressure_ind = n
        call interior_tendency_forcings(n)%add_forcing_field(field_source='internal', &
                      marbl_varname=marbl_varname, field_units=units,              &
                      driver_varname='pressure', rank=3, dim3_len=km, id=n)
      case ('Iron Sediment Flux')
        fesedflux_ind = n
        call interior_tendency_forcings(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,          &
                      unit_conv_factor=fesedflux_input%scale_factor,      &
                      rank=3, dim3_len=km, id=n)
      case ('O2 Consumption Scale Factor')
        select case (trim(o2_consumption_scalef_opt))
        case ('const')
          call interior_tendency_forcings(n)%add_forcing_field(field_source='const', &
               marbl_varname=marbl_varname, field_units=units, &
               field_constant=o2_consumption_scalef_const, rank=3, dim3_len=km, id=n)
        case ('file_time_invariant')
          call interior_tendency_forcings(n)%add_forcing_field( &
               field_source='file_time_invariant', &
               marbl_varname=marbl_varname, field_units=units, &
               filename=o2_consumption_scalef_input%filename, &
               file_varname=o2_consumption_scalef_input%file_varname, &
               unit_conv_factor=o2_consumption_scalef_input%scale_factor, &
               rank=3, dim3_len=km, id=n)
        case default
          call document(subname, 'unknown o2_consumption_scalef_opt', o2_consumption_scalef_opt)
          call exit_POP(sigAbort, 'Stopping in ' // subname)
        end select
      case ('Particulate Remin Scale Factor')
        select case (trim(p_remin_scalef_opt))
        case ('const')
          call interior_tendency_forcings(n)%add_forcing_field(field_source='const', &
               marbl_varname=marbl_varname, field_units=units, &
               field_constant=p_remin_scalef_const, rank=3, dim3_len=km, id=n)
        case ('file_time_invariant')
          call interior_tendency_forcings(n)%add_forcing_field( &
               field_source='file_time_invariant', &
               marbl_varname=marbl_varname, field_units=units, &
               filename=p_remin_scalef_input%filename, &
               file_varname=p_remin_scalef_input%file_varname, &
               unit_conv_factor=p_remin_scalef_input%scale_factor, &
               rank=3, dim3_len=km, id=n)
        case default
          call document(subname, 'unknown p_remin_scalef_opt', p_remin_scalef_opt)
          call exit_POP(sigAbort, 'Stopping in ' // subname)
        end select
      case DEFAULT
        write(err_msg, "(A,1X,A)") trim(marbl_req_interior_tendency_forcings(n)%metadata%varname), &
                       'is not a valid interior tendency forcing field name.'
        call document(subname, err_msg)
        call exit_POP(sigAbort, 'Stopping in ' // subname)
    end select
  end if

end do ! do n=1,size(interior_tendency_forcings)