From 75aa8f5627f93cd778ba8831f1f89dba3662a3bb Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Thu, 14 Dec 2023 13:25:25 -0700 Subject: [PATCH 01/35] Copied in the current versions of MARBL_state_estimation (developed in models/MARBL_MOM6_1D in branch marbl_mom6_1d) and MARBL_joint_estimation (developed in models/MARBL_MOM6_1D on branch param_estimation). --- .../observations/default_quantities_mod.f90 | 5 + .../observations/ocean_quantities_mod.f90 | 4 + .../modules/utilities/mpi_utilities_mod.f90 | 24 +- .../utilities/mpif08_utilities_mod.f90 | 24 +- .../utilities/null_mpi_utilities_mod.f90 | 24 +- models/MARBL_joint_estimation/model_mod.f90 | 653 ++++++++++++++++++ models/MARBL_joint_estimation/readme.rst | 5 + models/MARBL_joint_estimation/work/input.nml | 267 +++++++ .../work/output_mean.nc | Bin 0 -> 27140 bytes .../MARBL_joint_estimation/work/output_sd.nc | Bin 0 -> 27128 bytes .../MARBL_joint_estimation/work/quickbuild.sh | 59 ++ models/MARBL_state_estimation/model_mod.f90 | 652 +++++++++++++++++ models/MARBL_state_estimation/readme.rst | 5 + models/MARBL_state_estimation/work/input.nml | 238 +++++++ .../work/output_mean.nc | Bin 0 -> 27140 bytes .../MARBL_state_estimation/work/output_sd.nc | Bin 0 -> 27128 bytes .../MARBL_state_estimation/work/quickbuild.sh | 59 ++ 17 files changed, 1983 insertions(+), 36 deletions(-) create mode 100644 models/MARBL_joint_estimation/model_mod.f90 create mode 100644 models/MARBL_joint_estimation/readme.rst create mode 100644 models/MARBL_joint_estimation/work/input.nml create mode 100644 models/MARBL_joint_estimation/work/output_mean.nc create mode 100644 models/MARBL_joint_estimation/work/output_sd.nc create mode 100755 models/MARBL_joint_estimation/work/quickbuild.sh create mode 100644 models/MARBL_state_estimation/model_mod.f90 create mode 100644 models/MARBL_state_estimation/readme.rst create mode 100644 models/MARBL_state_estimation/work/input.nml create mode 100644 models/MARBL_state_estimation/work/output_mean.nc create mode 100644 models/MARBL_state_estimation/work/output_sd.nc create mode 100755 models/MARBL_state_estimation/work/quickbuild.sh diff --git a/assimilation_code/modules/observations/default_quantities_mod.f90 b/assimilation_code/modules/observations/default_quantities_mod.f90 index 84fc0cea8a..531116c603 100644 --- a/assimilation_code/modules/observations/default_quantities_mod.f90 +++ b/assimilation_code/modules/observations/default_quantities_mod.f90 @@ -72,6 +72,8 @@ ! QTY_CWP_PATH_ZERO ! QTY_DISSOLVED_INORGANIC_CARBON ! QTY_DISSOLVED_INORGANIC_IRON +! QTY_DISSOLVED_INORGANIC_SIO3 +! QTY_DISSOLVED_ORGANIC_CARBON ! QTY_DISSOLVED_ORGANIC_NITROGEN ! QTY_DISSOLVED_ORGANIC_P ! QTY_DISSOLVED_OXYGEN @@ -158,6 +160,7 @@ ! QTY_LANDMASK ! QTY_LARGE_SCALE_STATE desc="state varies with large time/space scale" ! QTY_LATENT_HEAT_FLUX +! QTY_LAYER_THICKNESS ! QTY_LEAF_AREA_INDEX ! QTY_LEAF_CARBON ! QTY_LEAF_NITROGEN @@ -167,7 +170,9 @@ ! QTY_LIVE_STEM_CARBON ! QTY_LIVE_STEM_NITROGEN ! QTY_MEAN_SOURCE +! QTY_MESOZOOPLANKTON_CARBON ! QTY_MICROWAVE_BRIGHT_TEMP +! QTY_MICROZOOPLANKTON_CARBON ! QTY_MINERAL_ACCUM ! QTY_MINERAL_COARSE ! QTY_MINERAL_NUCLEUS diff --git a/assimilation_code/modules/observations/ocean_quantities_mod.f90 b/assimilation_code/modules/observations/ocean_quantities_mod.f90 index fb4d0a3bc5..f53a0a6f7f 100644 --- a/assimilation_code/modules/observations/ocean_quantities_mod.f90 +++ b/assimilation_code/modules/observations/ocean_quantities_mod.f90 @@ -32,11 +32,15 @@ ! QTY_PHYTOPLANKTON_BIOMASS ! QTY_ALKALINITY ! QTY_DISSOLVED_INORGANIC_CARBON +! QTY_DISSOLVED_ORGANIC_CARBON ! QTY_DISSOLVED_ORGANIC_NITROGEN ! QTY_DISSOLVED_ORGANIC_P ! QTY_DISSOLVED_INORGANIC_IRON ! QTY_SURFACE_CHLOROPHYLL ! QTY_LAYER_THICKNESS +! QTY_DISSOLVED_INORGANIC_SIO3 +! QTY_MESOZOOPLANKTON_CARBON +! QTY_MICROZOOPLANKTON_CARBON ! ! ! fixme - these units are hardcoded in obs_diag and shouldn't be ! QTY_U_WIND_COMPONENT diff --git a/assimilation_code/modules/utilities/mpi_utilities_mod.f90 b/assimilation_code/modules/utilities/mpi_utilities_mod.f90 index 90797018e8..0f90677fa9 100644 --- a/assimilation_code/modules/utilities/mpi_utilities_mod.f90 +++ b/assimilation_code/modules/utilities/mpi_utilities_mod.f90 @@ -102,18 +102,18 @@ module mpi_utilities_mod ! this directory. It is a sed script that comments in and out the interface ! block below. Please leave the BLOCK comment lines unchanged. -! !!SYSTEM_BLOCK_EDIT START COMMENTED_OUT -! !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) -! ! interface block for getting return code back from system() routine -! interface -! function system(string) -! character(len=*) :: string -! integer :: system -! end function system -! end interface -! ! end block -! !#endif -! !!SYSTEM_BLOCK_EDIT END COMMENTED_OUT + !!SYSTEM_BLOCK_EDIT START COMMENTED_IN + !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) + ! interface block for getting return code back from system() routine + interface + function system(string) + character(len=*) :: string + integer :: system + end function system + end interface + ! end block + !#endif + !!SYSTEM_BLOCK_EDIT END COMMENTED_IN ! allow global sum to be computed for integers, r4, and r8s diff --git a/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 b/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 index dee8c618d1..4e423e1e6d 100644 --- a/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 +++ b/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 @@ -102,18 +102,18 @@ module mpi_utilities_mod ! this directory. It is a sed script that comments in and out the interface ! block below. Please leave the BLOCK comment lines unchanged. -! !!SYSTEM_BLOCK_EDIT START COMMENTED_OUT -! !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) -! ! interface block for getting return code back from system() routine -! interface -! function system(string) -! character(len=*) :: string -! integer :: system -! end function system -! end interface -! ! end block -! !#endif -! !!SYSTEM_BLOCK_EDIT END COMMENTED_OUT + !!SYSTEM_BLOCK_EDIT START COMMENTED_IN + !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) + ! interface block for getting return code back from system() routine + interface + function system(string) + character(len=*) :: string + integer :: system + end function system + end interface + ! end block + !#endif + !!SYSTEM_BLOCK_EDIT END COMMENTED_IN ! allow global sum to be computed for integers, r4, and r8s diff --git a/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 b/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 index cc729c23aa..30fa1d5ecd 100644 --- a/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 +++ b/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 @@ -74,18 +74,18 @@ module mpi_utilities_mod ! this directory. It is a sed script that comments in and out the interface ! block below. Please leave the BLOCK comment lines unchanged. -! !!SYSTEM_BLOCK_EDIT START COMMENTED_OUT -! !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) -! ! interface block for getting return code back from system() routine -! interface -! function system(string) -! character(len=*) :: string -! integer :: system -! end function system -! end interface -! ! end block -! !#endif -! !!SYSTEM_BLOCK_EDIT END COMMENTED_OUT + !!SYSTEM_BLOCK_EDIT START COMMENTED_IN + !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) + ! interface block for getting return code back from system() routine + interface + function system(string) + character(len=*) :: string + integer :: system + end function system + end interface + ! end block + !#endif + !!SYSTEM_BLOCK_EDIT END COMMENTED_IN ! allow global sum to be computed for integers, r4, and r8s diff --git a/models/MARBL_joint_estimation/model_mod.f90 b/models/MARBL_joint_estimation/model_mod.f90 new file mode 100644 index 0000000000..49ccdff50c --- /dev/null +++ b/models/MARBL_joint_estimation/model_mod.f90 @@ -0,0 +1,653 @@ +! DART software - Copyright UCAR. This open source software is provided +! by UCAR, "as is", without charge, subject to all terms of use at +! http://www.image.ucar.edu/DAReS/DART/DART_download +! + +module model_mod + +! This is a template showing the interfaces required for a model to be compliant +! with the DART data assimilation infrastructure. Do not change the arguments +! for the public routines. + +use types_mod, only : r8, i8, MISSING_R8, vtablenamelength + +use time_manager_mod, only : time_type, set_time + +use location_mod, only : location_type, get_close_type, & + loc_get_close_obs => get_close_obs, & + loc_get_close_state => get_close_state, & + set_location, set_location_missing, & + get_location, VERTISLEVEL + +use utilities_mod, only : register_module, error_handler, & + E_ERR, E_MSG, & + nmlfileunit, do_output, do_nml_file, do_nml_term, & + find_namelist_in_file, check_namelist_read, & + to_upper + +use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & + nc_add_global_creation_time, & + nc_begin_define_mode, nc_end_define_mode, & + NF90_MAX_NAME, nc_open_file_readonly, & + nc_get_variable, nc_get_variable_size, nc_close_file + +use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & + get_varid_from_kind, get_dart_vector_index + +use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & + QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & + QTY_LAYER_THICKNESS + +use distributed_state_mod, only: get_state + +use ensemble_manager_mod, only : ensemble_type + +! These routines are passed through from default_model_mod. +! To write model specific versions of these routines +! remove the routine from this use statement and add your code to +! this the file. +use default_model_mod, only : pert_model_copies, write_model_time, & + init_time => fail_init_time, & + init_conditions => fail_init_conditions, & + convert_vertical_obs, convert_vertical_state, adv_1step + +implicit none +private + +! routines required by DART code - will be called from filter and other +! DART executables. +public :: get_model_size, & + get_state_meta_data, & + model_interpolate, & + end_model, & + static_init_model, & + nc_write_model_atts, & + get_close_obs, & + get_close_state, & + pert_model_copies, & + convert_vertical_obs, & + convert_vertical_state, & + read_model_time, & + adv_1step, & + init_time, & + init_conditions, & + shortest_time_between_assimilations, & + write_model_time + + +character(len=256), parameter :: source = "model_mod.f90" +character(len=256), parameter :: ocean_geometry = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/baseline/ocean_geometry.nc" +logical :: module_initialized = .false. +integer :: state_dom_id ! used to access the state structure +integer :: param_dom_id ! used to access MARBL internal parameters +integer :: nfields ! number of fields in the state or parameter vector +integer :: nz ! the number of vertical layers +integer :: model_size +type(time_type) :: assimilation_time_step +real(r8), parameter :: geolon = 360 - 64.0 +real(r8), parameter :: geolat = 31.0 +real(r8) :: basin_depth(2,2) + +! parameters to be used in specifying the DART internal state +integer, parameter :: modelvar_table_height = 13 +integer, parameter :: modelvar_table_width = 5 +integer, parameter :: modelparams_table_height = 2 +integer, parameter :: modelparams_table_width = 5 + +! defining the variables that will be read from the namelist +character(len=256) :: template_file(2) +integer :: time_step_days +integer :: time_step_seconds +logical :: estimate_params +character(len=vtablenamelength) & + :: model_state_variables(modelvar_table_height * modelvar_table_width) +character(len=vtablenamelength) & + :: model_parameters(modelparams_table_height * modelparams_table_width) + +namelist /model_nml/ template_file, & + time_step_days, & + time_step_seconds, & + model_state_variables, & + estimate_params, & + model_parameters +contains + +!------------------------------------------------------------------ +! +! Called to do one time initialization of the model. As examples, +! might define information about the model size or model timestep. +! In models that require pre-computed static data, for instance +! spherical harmonic weights, these would also be computed here. + +subroutine static_init_model() + +integer :: iunit, io +character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width), & + param_table(modelparams_table_height, modelparams_table_width) +integer :: state_qty_list(modelvar_table_height), & + param_qty_list(modelparams_table_height) +real(r8):: state_clamp_vals(modelvar_table_height, 2), & + param_clamp_vals(modelparams_table_height, 2) +logical :: update_var_list(modelvar_table_height), & + update_param_list(modelparams_table_height) + +module_initialized = .true. + +! Print module information to log file and stdout. +call register_module(source) + +! Read values from the namelist + +call find_namelist_in_file("input.nml", "model_nml", iunit) +read(iunit, nml = model_nml, iostat = io) + +call check_namelist_read(iunit, io, "model_nml") + +! Record the namelist values used for the run +if (do_nml_file()) write(nmlfileunit, nml=model_nml) +if (do_nml_term()) write( * , nml=model_nml) + +! This time is both the minimum time you can ask the model to advance +! (for models that can be advanced by filter) and it sets the assimilation +! window. All observations within +/- 1/2 this interval from the current +! model time will be assimilated. If this is not settable at runtime +! feel free to hardcode it and remove from the namelist. +assimilation_time_step = set_time(time_step_seconds, & + time_step_days) + +! setting up the DART state vector +call verify_state_variables(model_state_variables, nfields, variable_table, & + state_qty_list, state_clamp_vals, update_var_list) + + state_dom_id = add_domain(template_file(1), nfields, & + var_names = variable_table(1:nfields, 1), & + kind_list = state_qty_list(1:nfields), & + clamp_vals = state_clamp_vals, & + update_list = update_var_list(1:nfields)) + +! setting up the DART parameter vector +if(estimate_params) then + call verify_state_variables(model_parameters, nfields, param_table, & + param_qty_list, param_clamp_vals, update_param_list) + + param_dom_id = add_domain(template_file(2), nfields, & + var_names = param_table(1:nfields, 1), & + kind_list = param_qty_list(1:nfields), & + clamp_vals = param_clamp_vals, & + update_list = update_param_list(1:nfields)) +end if + +call read_num_layers ! setting the value of nz +call read_ocean_geometry ! determining the basin depth + +end subroutine static_init_model + +!------------------------------------------------------------------ +! Reads the simulation length from a netCDF file. + +function read_model_time(filename) + +character(len=*), intent(in) :: filename +type(time_type) :: read_model_time + +integer :: ncid +character(len=*), parameter :: routine = 'read_model_time' +real(r8) :: days +type(time_type) :: mom6_time +integer :: mom_base_date_in_days, mom_days + +mom_base_date_in_days = 139157 ! 1982 1 1 0 0 +ncid = nc_open_file_readonly(filename, routine) + +call nc_get_variable(ncid, 'Time', days, routine) + +call nc_close_file(ncid, routine) + +mom_days = int(days) + mom_base_date_in_days + +read_model_time = set_time(0,mom_days) + +end function read_model_time + +!------------------------------------------------------------------ +! Returns the number of items in the state vector as an integer. + +function get_model_size() + +integer(i8) :: get_model_size + +if ( .not. module_initialized ) call static_init_model + +get_model_size = get_domain_size(state_dom_id) + get_domain_size(param_dom_id) + +end function get_model_size + +!------------------------------------------------------------------ +! Given a state handle, a location, and a state quantity, +! interpolates the state variable fields to that location and returns +! the values in expected_obs. The istatus variables should be returned as +! 0 unless there is some problem in computing the interpolation in +! which case a positive istatus should be returned. +! +! For applications in which only perfect model experiments +! with identity observations (i.e. only the value of a particular +! state variable is observed), this can be a NULL INTERFACE. + +subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus) + +type(ensemble_type), intent(in) :: state_handle +integer, intent(in) :: ens_size +type(location_type), intent(in) :: location +integer, intent(in) :: qty +real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values +integer, intent(out) :: istatus(ens_size) + +integer :: qty_id, thickness_id, layer_index +integer(i8) :: qty_index, thickness_index, ens_index +real(8) :: requested_depth, layerdepth_bottom, layerdepth_center, & + layerdepth_top, depth_below, depth_above, val_below, val_above +real(8) :: layer_thicknesses(nz, ens_size) +real(8) :: state_slice(ens_size) +real(8) :: loc_temp(3) + +if ( .not. module_initialized ) call static_init_model + +qty_id = get_varid_from_kind(state_dom_id, qty) + +! extracting the requested depth value from `location`. +loc_temp = get_location(location) +requested_depth = loc_temp(3) + +! print *, "REQUESTED DEPTH = ",requested_depth + +! extracting the current layer thicknesses for each ensemble member. +thickness_id = get_varid_from_kind(state_dom_id, QTY_LAYER_THICKNESS) + +do layer_index = 1, nz + ! layer thicknesses are always extracted from the grid cell at index (1, 1), since the four grid + ! cells are supposed to represent identical columns. + thickness_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, thickness_id) + layer_thicknesses(layer_index, :) = get_state(thickness_index, state_handle) +end do + +! performing the interpolation for each ensemble member individually. +do ens_index = 1, ens_size + ! print *, "BASIN DEPTH = ",-basin_depth(1,1) + ! print *, "----------------------------------------------------" + ! print *, "computing centers of layers" + ! print *, "----------------------------------------------------" + + ! locating the layer index to be used as the upper interpolation point for this ensemble member. + layer_index = nz + layerdepth_bottom = -basin_depth(1,1) ! depth at bottom of the layer given by layer_index. + layerdepth_center = layerdepth_bottom & ! depth at center of the layer given by layer_index. + + .5*layer_thicknesses(layer_index, ens_index) + layerdepth_top = layerdepth_bottom & ! depth at top of the layer given by layer_index. + + layer_thicknesses(layer_index, ens_index) + + ! print *, "layer = ",layer_index,", center = ",layerdepth_center,", bottom = ",layerdepth_bottom,", top = ",layerdepth_top + + do while((layerdepth_center < requested_depth) .and. (layer_index > 1)) + layer_index = layer_index - 1 + layerdepth_bottom = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) + layerdepth_center = layerdepth_bottom + 0.5 * layer_thicknesses(layer_index, ens_index) + layerdepth_top = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) + + ! print *, "layer = ",layer_index,", bottom = ",layerdepth_bottom,", center = ",layerdepth_center,", top = ",layerdepth_top + + end do + + ! having located the index of the upper interpolation layer, we now calculate the interpolation. + if((requested_depth < -basin_depth(1,1)) .or. (layerdepth_top < requested_depth)) then + ! case where the requested depth is below the ocean floor, or above the ocean surface + + ! print *, "----------------------------------------------------" + ! print *, "depth is below ocean floor or above ocean surface" + ! print *, "----------------------------------------------------" + + istatus(ens_index) = 1 + expected_obs(ens_index) = MISSING_R8 + + else if((layer_index == nz) .or. (layerdepth_center < requested_depth)) then + ! case where the requested depth is either in the bottom half of the deepest layer, + ! or the top half of the shallowest layer. In both cases, the "interpolated" value is + ! simply the current value of that layer in MOM6. + + ! print *, "----------------------------------------------------" + ! print *, "only using value from layer ",layer_index + ! print *, "----------------------------------------------------" + + istatus(ens_index) = 0 + qty_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, qty_id) + state_slice = get_state(qty_index, state_handle) + expected_obs(ens_index) = state_slice(ens_index) + + ! print *, "final value = ",expected_obs(ens_index) + + else + ! case where the requested depth is above the center of some layer, and below + ! the center of another. We interpolate linearly between the nearest layers above + ! and below. + + ! print *, "----------------------------------------------------" + ! print *, "interpolating between layers ",layer_index," and ",(layer_index + 1) + + istatus(ens_index) = 0 + + ! computing the depths at the centers of the nearest layers above and below + depth_above = layerdepth_center + depth_below = layerdepth_top - layer_thicknesses(layer_index, ens_index) & + - .5*layer_thicknesses(layer_index + 1, ens_index) + + ! extracting the quantity values at the layers above and below + qty_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, qty_id) + state_slice = get_state(qty_index, state_handle) + val_above = state_slice(ens_index) + + qty_index = get_dart_vector_index(1, 1, layer_index + 1, state_dom_id, qty_id) + state_slice = get_state(qty_index, state_handle) + val_below = state_slice(ens_index) + + ! print *, "corresponding to the values: ",val_above," and ",val_below + ! print *, "----------------------------------------------------" + + ! linear interpolation + expected_obs(ens_index) = val_above + (requested_depth - depth_above) * (val_below - val_above) / (depth_below - depth_above) + + ! print *, "final value = ",expected_obs(ens_index) + end if +end do + +end subroutine model_interpolate + + + +!------------------------------------------------------------------ +! Returns the smallest increment in time that the model is capable +! of advancing the state in a given implementation, or the shortest +! time you want the model to advance between assimilations. + +function shortest_time_between_assimilations() + +type(time_type) :: shortest_time_between_assimilations + +if ( .not. module_initialized ) call static_init_model + +shortest_time_between_assimilations = assimilation_time_step + +end function shortest_time_between_assimilations + + + +!------------------------------------------------------------------ +! Given an integer index into the state vector, returns the +! associated location and optionally the physical quantity. + +subroutine get_state_meta_data(index_in, location, qty) + +integer(i8), intent(in) :: index_in +type(location_type), intent(out) :: location +integer, intent(out), optional :: qty + +real(r8) :: lat, lon +integer :: lon_index, lat_index, level, local_qty + +if ( .not. module_initialized ) call static_init_model + +call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) + +location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) + +if (present(qty)) then + qty = local_qty +endif + + +end subroutine get_state_meta_data + + +!------------------------------------------------------------------ +! Any model specific distance calcualtion can be done here +subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & + num_close, close_ind, dist, ens_handle) + +type(get_close_type), intent(in) :: gc ! handle to a get_close structure +integer, intent(in) :: base_type ! observation TYPE +type(location_type), intent(inout) :: base_loc ! location of interest +type(location_type), intent(inout) :: locs(:) ! obs locations +integer, intent(in) :: loc_qtys(:) ! QTYS for obs +integer, intent(in) :: loc_types(:) ! TYPES for obs +integer, intent(out) :: num_close ! how many are close +integer, intent(out) :: close_ind(:) ! incidies into the locs array +real(r8), optional, intent(out) :: dist(:) ! distances in radians +type(ensemble_type), optional, intent(in) :: ens_handle + +character(len=*), parameter :: routine = 'get_close_obs' + +call loc_get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & + num_close, close_ind, dist, ens_handle) + +end subroutine get_close_obs + + +!------------------------------------------------------------------ +! Any model specific distance calcualtion can be done here +subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & + num_close, close_ind, dist, ens_handle) + +type(get_close_type), intent(in) :: gc ! handle to a get_close structure +type(location_type), intent(inout) :: base_loc ! location of interest +integer, intent(in) :: base_type ! observation TYPE +type(location_type), intent(inout) :: locs(:) ! state locations +integer, intent(in) :: loc_qtys(:) ! QTYs for state +integer(i8), intent(in) :: loc_indx(:) ! indices into DART state vector +integer, intent(out) :: num_close ! how many are close +integer, intent(out) :: close_ind(:) ! indices into the locs array +real(r8), optional, intent(out) :: dist(:) ! distances in radians +type(ensemble_type), optional, intent(in) :: ens_handle + +character(len=*), parameter :: routine = 'get_close_state' + + +call loc_get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & + num_close, close_ind, dist, ens_handle) + + +end subroutine get_close_state + + +!------------------------------------------------------------------ +! Does any shutdown and clean-up needed for model. Can be a NULL +! INTERFACE if the model has no need to clean up storage, etc. + +subroutine end_model() + + +end subroutine end_model + + +!------------------------------------------------------------------ +! write any additional attributes to the output and diagnostic files + +subroutine nc_write_model_atts(ncid, domain_id) + +integer, intent(in) :: ncid ! netCDF file identifier +integer, intent(in) :: domain_id + +if ( .not. module_initialized ) call static_init_model + +! put file into define mode. + +call nc_begin_define_mode(ncid) + +call nc_add_global_creation_time(ncid) + +call nc_add_global_attribute(ncid, "model_source", source ) +call nc_add_global_attribute(ncid, "model", "template") + +call nc_end_define_mode(ncid) + +! Flush the buffer and leave netCDF file open +call nc_synchronize_file(ncid) + +end subroutine nc_write_model_atts + +!------------------------------------------------------------------ +! Verify that the namelist was filled in correctly, and check +! that there are valid entries for the dart_kind. +! Returns a table with columns: +! +! netcdf_variable_name ; dart_qty_string ; lowerbound ; upperbound ; update_string + +subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp_vals, update_var) + +character(len=*), intent(inout) :: state_variables(:) +integer, intent(out) :: ngood +character(len=*), intent(out) :: table(:,:) +integer, intent(out) :: qty_list(:) ! kind number +real(r8), intent(out) :: clamp_vals(:,:) +logical, intent(out) :: update_var(:) ! logical update + +integer :: nrows, i +character(len=NF90_MAX_NAME) :: varname, dartstr, lowerbound, upperbound, update +character(len=256) :: string1, string2 + +if ( .not. module_initialized ) call static_init_model + +nrows = size(table,1) + +ngood = 0 + +MyLoop : do i = 1, nrows + + varname = trim(state_variables(5*i -4)) + dartstr = trim(state_variables(5*i -3)) + lowerbound = trim(state_variables(5*i -2)) + upperbound = trim(state_variables(5*i -1)) + update = trim(state_variables(5*i )) + + call to_upper(update) + + table(i,1) = trim(varname) + table(i,2) = trim(dartstr) + table(i,3) = trim(lowerbound) + table(i,4) = trim(upperbound) + table(i,5) = trim(update) + + if ( table(i,1) == ' ' .and. table(i,2) == ' ' .and. table(i,3) == ' ' .and. table(i,4) == ' ' .and. table(i,5) == ' ') exit MyLoop ! Found end of list. + + if ( table(i,1) == ' ' .or. table(i,2) == ' ' .or. table(i,3) == ' ' .or. table(i,4) == ' ' .or. table(i,5) == ' ') then + string1 = 'model_nml:model_state_variables not fully specified' + call error_handler(E_ERR,'verify_state_variables',string1) + endif + + ! Make sure DART qty is valid + + qty_list(i) = get_index_for_quantity(dartstr) + if( qty_list(i) < 0 ) then + write(string1,'(''there is no obs_kind <'',a,''> in obs_kind_mod.f90'')') trim(dartstr) + call error_handler(E_ERR,'verify_state_variables',string1) + endif + + ! Make sure the update variable has a valid name + + select case (update) + case ('UPDATE') + update_var(i) = .true. + case ('NO_COPY_BACK') + update_var(i) = .false. + case default + write(string1,'(A)') 'only UPDATE or NO_COPY_BACK supported in model_state_variable namelist' + write(string2,'(6A)') 'you provided : ', trim(varname), ', ', trim(dartstr), ', ', trim(update) + call error_handler(E_ERR,'verify_state_variables',string1, text2=string2) + end select + + ! reading the clamp values + + if (table(i, 3) /= 'NA') then + read(table(i,3), '(d16.8)') clamp_vals(i,1) + else + clamp_vals(i,1) = MISSING_R8 + endif + + if (table(i,4) /= 'NA') then + read(table(i,4), '(d16.8)') clamp_vals(i,2) + else + clamp_vals(i,2) = MISSING_R8 + endif + + ngood = ngood + 1 +enddo MyLoop + + +end subroutine verify_state_variables + +!------------------------------------------------------------ +function on_v_grid(qty) + +integer, intent(in) :: qty +logical :: on_v_grid + +if (qty == QTY_V_CURRENT_COMPONENT) then + on_v_grid = .true. +else + on_v_grid = .false. +endif + +end function on_v_grid + +!---------------------------------------------------------- +function on_u_grid(qty) + +integer, intent(in) :: qty +logical :: on_u_grid + +if (qty == QTY_U_CURRENT_COMPONENT) then + on_u_grid = .true. +else + on_u_grid = .false. +endif + +end function on_u_grid + +!------------------------------------------------------------ +! Read number of vertical layers from mom6 template file +subroutine read_num_layers() + +integer :: ncid + +character(len=*), parameter :: routine = 'read_num_layers' + +ncid = nc_open_file_readonly(template_file(1)) + +call nc_get_variable_size(ncid, 'Layer', nz) + +call nc_close_file(ncid) + +end subroutine read_num_layers + +!------------------------------------------------------------ +! ocean_geom are 2D state sized static data +! HK Do these arrays become too big in high res cases? +subroutine read_ocean_geometry() + +integer :: ncid + +character(len=*), parameter :: routine = 'read_ocean_geometry' + +! Need nx, ny +if ( .not. module_initialized ) call static_init_model + +ncid = nc_open_file_readonly(ocean_geometry) + +call nc_get_variable(ncid, 'D', basin_depth, routine) + +call nc_close_file(ncid) + +end subroutine read_ocean_geometry + +!=================================================================== +! End of model_mod +!=================================================================== +end module model_mod + diff --git a/models/MARBL_joint_estimation/readme.rst b/models/MARBL_joint_estimation/readme.rst new file mode 100644 index 0000000000..9119443802 --- /dev/null +++ b/models/MARBL_joint_estimation/readme.rst @@ -0,0 +1,5 @@ +MARBL_joint_estimation +======================= + +.. attention:: + Add your model documentation here. diff --git a/models/MARBL_joint_estimation/work/input.nml b/models/MARBL_joint_estimation/work/input.nml new file mode 100644 index 0000000000..1e534465c3 --- /dev/null +++ b/models/MARBL_joint_estimation/work/input.nml @@ -0,0 +1,267 @@ +&perfect_model_obs_nml + read_input_state_from_file = .true., + single_file_in = .false., + input_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/RESTART/DART_perfect_model_obs/MOM.res.nc", + + write_output_state_to_file = .true., + single_file_out = .false., + output_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/RESTART/DART_perfect_model_obs/MOM.res.output.nc", + output_interval = 1, + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_seq_in_file_name = "obs_seq.in", + obs_seq_out_file_name = "obs_seq.out", + init_time_days = 0, + init_time_seconds = 0, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + trace_execution = .false., + output_timestamps = .false., + print_every_nth_obs = -1, + output_forward_op_errors = .false., + silence = .false., + / + +&filter_nml + single_file_in = .false., + input_state_files = '', + input_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_params.txt', + + stages_to_write = 'preassim', 'analysis', 'output', + + single_file_out = .false., + output_state_files = '', + output_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_params.txt', + output_interval = 1, + output_members = .true., + num_output_state_members = 80, + output_mean = .true., + output_sd = .true., + write_all_stages_at_end = .true., + + ens_size = 80, + num_groups = 2, + perturb_from_single_instance = .false., + perturbation_amplitude = 1e-2, + distributed_state = .true., + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_sequence_in_name ='/glade/u/home/rarmstrong/work/BATS_joint_estimation_obsseq/BATS_joint_estimation_147612.out', + obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/output/147612/obs_seq.final', + num_output_obs_members = 80, + init_time_days = -1, + init_time_seconds = -1, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + inf_flavor = 5, 0, + inf_initial_from_restart = .true., .false., + inf_sd_initial_from_restart = .true., .false., + inf_deterministic = .true., .true., + inf_initial = 1.0, 1.0, + inf_lower_bound = 0.0, 1.0, + inf_upper_bound = 100.0, 1000000.0, + inf_damping = 0.9, 1.0, + inf_sd_initial = 0.6, 0.0, + inf_sd_lower_bound = 0.6, 0.0, + inf_sd_max_change = 1.05, 1.05, + + trace_execution = .true., + output_timestamps = .false., + output_forward_op_errors = .false., + silence = .false., + / + +&fill_inflation_restart_nml + write_prior_inf = .true., + prior_inf_mean = 1.0, + prior_inf_sd = 0.6, + + write_post_inf = .false., + post_inf_mean = 1.00, + post_inf_sd = 0.6, + + input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc', + single_file = .false., + verbose = .false. + / + + +&ensemble_manager_nml + / + +&assim_tools_nml + filter_kind = 1, + cutoff = 1000000.0 + sort_obs_inc = .false., + spread_restoration = .false., + sampling_error_correction = .false., + adaptive_localization_threshold = -1, + distribute_mean = .false. + output_localization_diagnostics = .false., + localization_diagnostics_file = 'localization_diagnostics', + print_every_nth_obs = 0 + / + +&cov_cutoff_nml + select_localization = 1 + / + +®_factor_nml + select_regression = 1, + input_reg_file = "time_mean_reg", + save_reg_diagnostics = .false., + reg_diagnostics_file = "reg_diagnostics" + / + +&obs_sequence_nml + write_binary_obs_sequence = .false. + / + +&obs_kind_nml + assimilate_these_obs_types = 'POLY_ELECTRODE_OXYGEN', + 'TITRATION_ALKALINITY', + 'CATALYTIC_CARBON', + 'UV_OXY_NITROGEN', + 'CFA_SILICATE', + 'CFA_PHOSPHATE', + 'CFA_NITRATE' + evaluate_these_obs_types = '' + / + +&model_nml + template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc', + time_step_days = 1, + time_step_seconds = 0, + model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', + 'PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', + 'DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', + 'O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', + 'DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', + 'DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', + 'DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', + 'ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', + 'microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' + estimate_params = .true. + model_parameters = 'autotroph_settings(1)%kCO2 ', 'QTY_PARAM_AUTOTROPH1_KCO2 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kFe ', 'QTY_PARAM_AUTOTROPH1_KFE ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kNO3 ', 'QTY_PARAM_AUTOTROPH1_KNO3 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kPO4 ', 'QTY_PARAM_AUTOTROPH1_KPO4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kSiO3', 'QTY_PARAM_AUTOTROPH1_KSIO3', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kCO2 ', 'QTY_PARAM_AUTOTROPH2_KCO2 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kDOP ', 'QTY_PARAM_AUTOTROPH2_KDOP ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kFe ', 'QTY_PARAM_AUTOTROPH2_KFE ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kNH4 ', 'QTY_PARAM_AUTOTROPH2_KNH4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kNO3 ', 'QTY_PARAM_AUTOTROPH2_KNO3 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kPO4 ', 'QTY_PARAM_AUTOTROPH2_KPO4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(2)%kSiO3', 'QTY_PARAM_AUTOTROPH2_KSIO3', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kCO2 ', 'QTY_PARAM_AUTOTROPH3_KCO2 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kDOP ', 'QTY_PARAM_AUTOTROPH3_KDOP ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kFe ', 'QTY_PARAM_AUTOTROPH3_KFE ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kNO3 ', 'QTY_PARAM_AUTOTROPH3_KNO3 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kNH4 ', 'QTY_PARAM_AUTOTROPH3_KNH4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kPO4 ', 'QTY_PARAM_AUTOTROPH3_KPO4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(3)%kSiO3', 'QTY_PARAM_AUTOTROPH3_KSIO3', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kCO2 ', 'QTY_PARAM_AUTOTROPH4_KCO2 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kDOP ', 'QTY_PARAM_AUTOTROPH4_KDOP ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kFe ', 'QTY_PARAM_AUTOTROPH4_KFE ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kNO3 ', 'QTY_PARAM_AUTOTROPH4_KNO3 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kNH4 ', 'QTY_PARAM_AUTOTROPH4_KNH4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kPO4 ', 'QTY_PARAM_AUTOTROPH4_KPO4 ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(4)%kSiO3', 'QTY_PARAM_AUTOTROPH4_KSIO3', '0.0', 'NA', 'UPDATE' + / + +&utilities_nml + TERMLEVEL = 1, + module_details = .false., + logfilename = 'dart_log.out', + nmlfilename = 'dart_log.nml', + write_nml = 'none' + / + +&preprocess_nml + input_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/default_quantities_mod.f90', '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/ocean_quantities_mod.f90' + / + +&obs_sequence_tool_nml + filename_seq = 'obs_seq.one', 'obs_seq.two', + filename_out = 'obs_seq.processed', + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + print_only = .false., + gregorian_cal = .false. + / + +&obs_diag_nml + obs_sequence_name = '' + obs_sequence_list = 'obs_diag_files/obs_seq_list.txt' + first_bin_center = 2005, 2, 24, 0, 0, 0 + last_bin_center = 2006, 2, 22, 0, 0, 0 + bin_separation = 0, 0, 1, 0, 0, 0 + bin_width = 0, 0, 1, 0, 0, 0 + time_to_skip = 0, 0, 0, 0, 0, 0 + max_num_bins = 1000 + plevel = -888888.0 + hlevel = -1, -5, -10, -50, -100, -250, -500, -1000, -2000, -3000, -4000, -5000, -6000 + mlevel = -888888 + plevel_edges = -888888.0 + hlevel_edges = -888888.0 + mlevel_edges = -888888 + Nregions = 1 + lonlim1 = 0 + lonlim2 = 360 + latlim1 = -90 + latlim2 = 90 + reg_names = 'null' + trusted_obs = 'null' + create_rank_histogram = .true. + outliers_in_histogram = .false. + use_zero_error_obs = .false. + verbose = .false. + / + +&state_vector_io_nml + / + +&model_mod_check_nml + input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' + output_state_files = 'testing/model_mod_check_output/output.nc' + test1thru = 0, + run_tests = 1,2,3,4,5,6,7 + x_ind = 261 + loc_of_interest = 1.11, 0.54, -500.0 + quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_NITROGEN' + interp_test_dx = 0.02 + interp_test_xrange = 0.0, 1.0 + verbose = .true. + / + +&quality_control_nml + input_qc_threshold = 3.0, + outlier_threshold = 3.0, +/ + +&location_nml + / diff --git a/models/MARBL_joint_estimation/work/output_mean.nc b/models/MARBL_joint_estimation/work/output_mean.nc new file mode 100644 index 0000000000000000000000000000000000000000..62479604a15655cb2f94ee6cce37dd8c804e1bbf GIT binary patch literal 27140 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 get_close_obs, & + loc_get_close_state => get_close_state, & + set_location, set_location_missing, & + get_location, VERTISLEVEL + +use utilities_mod, only : register_module, error_handler, & + E_ERR, E_MSG, & + nmlfileunit, do_output, do_nml_file, do_nml_term, & + find_namelist_in_file, check_namelist_read, & + to_upper + +use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & + nc_add_global_creation_time, & + nc_begin_define_mode, nc_end_define_mode, & + NF90_MAX_NAME, nc_open_file_readonly, & + nc_get_variable, nc_get_variable_size, nc_close_file + +use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & + get_varid_from_kind, get_dart_vector_index + +use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & + QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & + QTY_LAYER_THICKNESS + +use distributed_state_mod, only: get_state + +use ensemble_manager_mod, only : ensemble_type + +! These routines are passed through from default_model_mod. +! To write model specific versions of these routines +! remove the routine from this use statement and add your code to +! this the file. +use default_model_mod, only : pert_model_copies, write_model_time, & + init_time => fail_init_time, & + init_conditions => fail_init_conditions, & + convert_vertical_obs, convert_vertical_state, adv_1step + +implicit none +private + +! routines required by DART code - will be called from filter and other +! DART executables. +public :: get_model_size, & + get_state_meta_data, & + model_interpolate, & + end_model, & + static_init_model, & + nc_write_model_atts, & + get_close_obs, & + get_close_state, & + pert_model_copies, & + convert_vertical_obs, & + convert_vertical_state, & + read_model_time, & + adv_1step, & + init_time, & + init_conditions, & + shortest_time_between_assimilations, & + write_model_time + + +character(len=256), parameter :: source = "model_mod.f90" +character(len=256), parameter :: ocean_geometry = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/ensemble/baseline/ocean_geometry.nc" +logical :: module_initialized = .false. +integer :: dom_id ! used to access the state structure +integer :: nfields ! number of fields in the state vector +integer :: nz ! the number of vertical layers +integer :: model_size +type(time_type) :: assimilation_time_step +real(r8), parameter :: geolon = 360 - 64.0 +real(r8), parameter :: geolat = 31.0 +real(r8) :: basin_depth(2,2) + +logical, parameter :: debug_interpolation = .false. + +! parameters to be used in specifying the DART internal state +integer, parameter :: modelvar_table_height = 13 +integer, parameter :: modelvar_table_width = 5 + +! defining the variables that will be read from the namelist +character(len=256) :: template_file +integer :: time_step_days +integer :: time_step_seconds +character(len=vtablenamelength) & + :: model_state_variables(modelvar_table_height * modelvar_table_width) + +namelist /model_nml/ template_file, & + time_step_days, & + time_step_seconds, & + model_state_variables + +contains + +!------------------------------------------------------------------ +! +! Called to do one time initialization of the model. As examples, +! might define information about the model size or model timestep. +! In models that require pre-computed static data, for instance +! spherical harmonic weights, these would also be computed here. + +subroutine static_init_model() + +integer :: iunit, io +character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width) +integer :: state_qty_list(modelvar_table_height) +real(r8):: state_clamp_vals(modelvar_table_height, 2) +logical :: update_var_list(modelvar_table_height) + +module_initialized = .true. + +! Print module information to log file and stdout. +call register_module(source) + +! Read values from the namelist + +call find_namelist_in_file("input.nml", "model_nml", iunit) +read(iunit, nml = model_nml, iostat = io) + +call check_namelist_read(iunit, io, "model_nml") + +! Record the namelist values used for the run +if (do_nml_file()) write(nmlfileunit, nml=model_nml) +if (do_nml_term()) write( * , nml=model_nml) + +! This time is both the minimum time you can ask the model to advance +! (for models that can be advanced by filter) and it sets the assimilation +! window. All observations within +/- 1/2 this interval from the current +! model time will be assimilated. If this is not settable at runtime +! feel free to hardcode it and remove from the namelist. +assimilation_time_step = set_time(time_step_seconds, & + time_step_days) + +call verify_state_variables(model_state_variables, nfields, variable_table, & + state_qty_list, state_clamp_vals, update_var_list) + +! print *, "variable_table = ",variable_table +! print *, "state_qty_list = ",state_qty_list +! print *, "state_clamp_vals = ",state_clamp_vals +! print *, "update_var_list = ",update_var_list + +dom_id = add_domain(template_file, nfields, & + var_names = variable_table(1:nfields, 1), & + kind_list = state_qty_list(1:nfields), & + clamp_vals = state_clamp_vals, & + update_list = update_var_list(1:nfields)) + +model_size = get_domain_size(dom_id) + +call read_num_layers ! setting the value of nz +call read_ocean_geometry ! determining the basin depth + +end subroutine static_init_model + +!------------------------------------------------------------------ +! Reads the simulation length from a netCDF file. + +function read_model_time(filename) + +character(len=*), intent(in) :: filename +type(time_type) :: read_model_time + +integer :: ncid +character(len=*), parameter :: routine = 'read_model_time' +real(r8) :: days +type(time_type) :: mom6_time +integer :: mom_base_date_in_days, mom_days + +mom_base_date_in_days = 139157 ! 1982 1 1 0 0 +ncid = nc_open_file_readonly(filename, routine) + +call nc_get_variable(ncid, 'Time', days, routine) + +call nc_close_file(ncid, routine) + +mom_days = int(days) + mom_base_date_in_days + +read_model_time = set_time(0,mom_days) + +end function read_model_time + +!------------------------------------------------------------------ +! Returns the number of items in the state vector as an integer. + +function get_model_size() + +integer(i8) :: get_model_size + +if ( .not. module_initialized ) call static_init_model + +get_model_size = get_domain_size(dom_id) + +end function get_model_size + +!------------------------------------------------------------------ +! Given a state handle, a location, and a state quantity, +! interpolates the state variable fields to that location and returns +! the values in expected_obs. The istatus variables should be returned as +! 0 unless there is some problem in computing the interpolation in +! which case a positive istatus should be returned. +! +! For applications in which only perfect model experiments +! with identity observations (i.e. only the value of a particular +! state variable is observed), this can be a NULL INTERFACE. + +subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus) + +type(ensemble_type), intent(in) :: state_handle +integer, intent(in) :: ens_size +type(location_type), intent(in) :: location +integer, intent(in) :: qty +real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values +integer, intent(out) :: istatus(ens_size) + +integer :: qty_id, thickness_id, layer_index +integer(i8) :: qty_index, thickness_index, ens_index +real(8) :: requested_depth, layerdepth_bottom, layerdepth_center, & + layerdepth_top, depth_below, depth_above, val_below, val_above +real(8) :: layer_thicknesses(nz, ens_size) +real(8) :: state_slice(ens_size) +real(8) :: loc_temp(3) + +if ( .not. module_initialized ) call static_init_model + +qty_id = get_varid_from_kind(dom_id, qty) + +! extracting the requested depth value from `location`. +loc_temp = get_location(location) +requested_depth = loc_temp(3) + +if(debug_interpolation) then; print *, "REQUESTED DEPTH = ",requested_depth; end if + +! extracting the current layer thicknesses for each ensemble member. +thickness_id = get_varid_from_kind(dom_id, QTY_LAYER_THICKNESS) + +do layer_index = 1, nz + ! layer thicknesses are always extracted from the grid cell at index (1, 1), since the four grid + ! cells are supposed to represent identical columns. + thickness_index = get_dart_vector_index(1, 1, layer_index, dom_id, thickness_id) + layer_thicknesses(layer_index, :) = get_state(thickness_index, state_handle) +end do + +! performing the interpolation for each ensemble member individually. +do ens_index = 1, ens_size + if(debug_interpolation) then + print *, "BASIN DEPTH = ",-basin_depth(1,1) + print *, "----------------------------------------------------" + print *, "computing centers of layers" + print *, "----------------------------------------------------" + end if + + ! locating the layer index to be used as the upper interpolation point for this ensemble member. + layer_index = nz + layerdepth_bottom = -basin_depth(1,1) ! depth at bottom of the layer given by layer_index. + layerdepth_center = layerdepth_bottom & ! depth at center of the layer given by layer_index. + + .5*layer_thicknesses(layer_index, ens_index) + layerdepth_top = layerdepth_bottom & ! depth at top of the layer given by layer_index. + + layer_thicknesses(layer_index, ens_index) + + if(debug_interpolation) then + print *, "layer = ",layer_index,", center = ",layerdepth_center,", bottom = ",layerdepth_bottom,", top = ",layerdepth_top + end if + + do while((layerdepth_center < requested_depth) .and. (layer_index > 1)) + layer_index = layer_index - 1 + layerdepth_bottom = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) + layerdepth_center = layerdepth_bottom + 0.5 * layer_thicknesses(layer_index, ens_index) + layerdepth_top = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) + + if(debug_interpolation) then + print *, "layer = ",layer_index,", bottom = ",layerdepth_bottom,", center = ",layerdepth_center,", top = ",layerdepth_top + end if + + end do + + ! having located the index of the upper interpolation layer, we now calculate the interpolation. + if((requested_depth < -basin_depth(1,1)) .or. (layerdepth_top < requested_depth)) then + ! case where the requested depth is below the ocean floor, or above the ocean surface + + if(debug_interpolation) then + print *, "----------------------------------------------------" + print *, "depth is below ocean floor or above ocean surface" + print *, "----------------------------------------------------" + end if + + istatus(ens_index) = 1 + expected_obs(ens_index) = MISSING_R8 + + else if((layer_index == nz) .or. (layerdepth_center < requested_depth)) then + ! case where the requested depth is either in the bottom half of the deepest layer, + ! or the top half of the shallowest layer. In both cases, the "interpolated" value is + ! simply the current value of that layer in MOM6. + + if(debug_interpolation) then + print *, "----------------------------------------------------" + print *, "only using value from layer ",layer_index + print *, "----------------------------------------------------" + end if + + istatus(ens_index) = 0 + qty_index = get_dart_vector_index(1, 1, layer_index, dom_id, qty_id) + state_slice = get_state(qty_index, state_handle) + expected_obs(ens_index) = state_slice(ens_index) + + if(debug_interpolation) then; print *, "final value = ",expected_obs(ens_index); end if + + else + ! case where the requested depth is above the center of some layer, and below + ! the center of another. We interpolate linearly between the nearest layers above + ! and below. + + if(debug_interpolation) then + print *, "----------------------------------------------------" + print *, "interpolating between layers ",layer_index," and ",(layer_index + 1) + end if + + istatus(ens_index) = 0 + + ! computing the depths at the centers of the nearest layers above and below + depth_above = layerdepth_center + depth_below = layerdepth_top - layer_thicknesses(layer_index, ens_index) & + - .5*layer_thicknesses(layer_index + 1, ens_index) + + ! extracting the quantity values at the layers above and below + qty_index = get_dart_vector_index(1, 1, layer_index, dom_id, qty_id) + state_slice = get_state(qty_index, state_handle) + val_above = state_slice(ens_index) + + qty_index = get_dart_vector_index(1, 1, layer_index + 1, dom_id, qty_id) + state_slice = get_state(qty_index, state_handle) + val_below = state_slice(ens_index) + + if(debug_interpolation) then + print *, "corresponding to the values: ",val_above," and ",val_below + print *, "----------------------------------------------------" + end if + + ! linear interpolation + expected_obs(ens_index) = val_above + (requested_depth - depth_above) * (val_below - val_above) / (depth_below - depth_above) + + if(debug_interpolation) then; print *, "final value = ",expected_obs(ens_index); end if + end if +end do + +end subroutine model_interpolate + + + +!------------------------------------------------------------------ +! Returns the smallest increment in time that the model is capable +! of advancing the state in a given implementation, or the shortest +! time you want the model to advance between assimilations. + +function shortest_time_between_assimilations() + +type(time_type) :: shortest_time_between_assimilations + +if ( .not. module_initialized ) call static_init_model + +shortest_time_between_assimilations = assimilation_time_step + +end function shortest_time_between_assimilations + + + +!------------------------------------------------------------------ +! Given an integer index into the state vector, returns the +! associated location and optionally the physical quantity. + +subroutine get_state_meta_data(index_in, location, qty) + +integer(i8), intent(in) :: index_in +type(location_type), intent(out) :: location +integer, intent(out), optional :: qty + +real(r8) :: lat, lon +integer :: lon_index, lat_index, level, local_qty + +if ( .not. module_initialized ) call static_init_model + +call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) + +location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) + +if (present(qty)) then + qty = local_qty +endif + + +end subroutine get_state_meta_data + + +!------------------------------------------------------------------ +! Any model specific distance calcualtion can be done here +subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & + num_close, close_ind, dist, ens_handle) + +type(get_close_type), intent(in) :: gc ! handle to a get_close structure +integer, intent(in) :: base_type ! observation TYPE +type(location_type), intent(inout) :: base_loc ! location of interest +type(location_type), intent(inout) :: locs(:) ! obs locations +integer, intent(in) :: loc_qtys(:) ! QTYS for obs +integer, intent(in) :: loc_types(:) ! TYPES for obs +integer, intent(out) :: num_close ! how many are close +integer, intent(out) :: close_ind(:) ! incidies into the locs array +real(r8), optional, intent(out) :: dist(:) ! distances in radians +type(ensemble_type), optional, intent(in) :: ens_handle + +character(len=*), parameter :: routine = 'get_close_obs' + +call loc_get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & + num_close, close_ind, dist, ens_handle) + +end subroutine get_close_obs + + +!------------------------------------------------------------------ +! Any model specific distance calcualtion can be done here +subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & + num_close, close_ind, dist, ens_handle) + +type(get_close_type), intent(in) :: gc ! handle to a get_close structure +type(location_type), intent(inout) :: base_loc ! location of interest +integer, intent(in) :: base_type ! observation TYPE +type(location_type), intent(inout) :: locs(:) ! state locations +integer, intent(in) :: loc_qtys(:) ! QTYs for state +integer(i8), intent(in) :: loc_indx(:) ! indices into DART state vector +integer, intent(out) :: num_close ! how many are close +integer, intent(out) :: close_ind(:) ! indices into the locs array +real(r8), optional, intent(out) :: dist(:) ! distances in radians +type(ensemble_type), optional, intent(in) :: ens_handle + +character(len=*), parameter :: routine = 'get_close_state' + + +call loc_get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & + num_close, close_ind, dist, ens_handle) + + +end subroutine get_close_state + + +!------------------------------------------------------------------ +! Does any shutdown and clean-up needed for model. Can be a NULL +! INTERFACE if the model has no need to clean up storage, etc. + +subroutine end_model() + + +end subroutine end_model + + +!------------------------------------------------------------------ +! write any additional attributes to the output and diagnostic files + +subroutine nc_write_model_atts(ncid, domain_id) + +integer, intent(in) :: ncid ! netCDF file identifier +integer, intent(in) :: domain_id + +if ( .not. module_initialized ) call static_init_model + +! put file into define mode. + +call nc_begin_define_mode(ncid) + +call nc_add_global_creation_time(ncid) + +call nc_add_global_attribute(ncid, "model_source", source ) +call nc_add_global_attribute(ncid, "model", "template") + +call nc_end_define_mode(ncid) + +! Flush the buffer and leave netCDF file open +call nc_synchronize_file(ncid) + +end subroutine nc_write_model_atts + +!------------------------------------------------------------------ +! Verify that the namelist was filled in correctly, and check +! that there are valid entries for the dart_kind. +! Returns a table with columns: +! +! netcdf_variable_name ; dart_qty_string ; update_string + +subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp_vals, update_var) + +character(len=*), intent(inout) :: state_variables(:) +integer, intent(out) :: ngood +character(len=*), intent(out) :: table(:,:) +integer, intent(out) :: qty_list(:) ! kind number +real(r8), intent(out) :: clamp_vals(:,:) +logical, intent(out) :: update_var(:) ! logical update + +integer :: nrows, i +character(len=NF90_MAX_NAME) :: varname, dartstr, lowerbound, upperbound, update +character(len=256) :: string1, string2 + +if ( .not. module_initialized ) call static_init_model + +nrows = size(table,1) + +ngood = 0 + +MyLoop : do i = 1, nrows + + varname = trim(state_variables(5*i -4)) + dartstr = trim(state_variables(5*i -3)) + lowerbound = trim(state_variables(5*i -2)) + upperbound = trim(state_variables(5*i -1)) + update = trim(state_variables(5*i )) + + call to_upper(update) + + table(i,1) = trim(varname) + table(i,2) = trim(dartstr) + table(i,3) = trim(lowerbound) + table(i,4) = trim(upperbound) + table(i,5) = trim(update) + + if ( table(i,1) == ' ' .and. table(i,2) == ' ' .and. table(i,3) == ' ' .and. table(i,4) == ' ' .and. table(i,5) == ' ') exit MyLoop ! Found end of list. + + if ( table(i,1) == ' ' .or. table(i,2) == ' ' .or. table(i,3) == ' ' .or. table(i,4) == ' ' .or. table(i,5) == ' ') then + string1 = 'model_nml:model_state_variables not fully specified' + call error_handler(E_ERR,'verify_state_variables',string1) + endif + + ! Make sure DART qty is valid + + qty_list(i) = get_index_for_quantity(dartstr) + if( qty_list(i) < 0 ) then + write(string1,'(''there is no obs_kind <'',a,''> in obs_kind_mod.f90'')') trim(dartstr) + call error_handler(E_ERR,'verify_state_variables',string1) + endif + + ! Make sure the update variable has a valid name + + select case (update) + case ('UPDATE') + update_var(i) = .true. + case ('NO_COPY_BACK') + update_var(i) = .false. + case default + write(string1,'(A)') 'only UPDATE or NO_COPY_BACK supported in model_state_variable namelist' + write(string2,'(6A)') 'you provided : ', trim(varname), ', ', trim(dartstr), ', ', trim(update) + call error_handler(E_ERR,'verify_state_variables',string1, text2=string2) + end select + + ! reading the clamp values + + if (table(i, 3) /= 'NA') then + read(table(i,3), '(d16.8)') clamp_vals(i,1) + else + clamp_vals(i,1) = MISSING_R8 + endif + + if (table(i,4) /= 'NA') then + read(table(i,4), '(d16.8)') clamp_vals(i,2) + else + clamp_vals(i,2) = MISSING_R8 + endif + + ngood = ngood + 1 +enddo MyLoop + + +end subroutine verify_state_variables + +!------------------------------------------------------------ +function on_v_grid(qty) + +integer, intent(in) :: qty +logical :: on_v_grid + +if (qty == QTY_V_CURRENT_COMPONENT) then + on_v_grid = .true. +else + on_v_grid = .false. +endif + +end function on_v_grid + +!---------------------------------------------------------- +function on_u_grid(qty) + +integer, intent(in) :: qty +logical :: on_u_grid + +if (qty == QTY_U_CURRENT_COMPONENT) then + on_u_grid = .true. +else + on_u_grid = .false. +endif + +end function on_u_grid + +!------------------------------------------------------------ +! Read number of vertical layers from mom6 template file +subroutine read_num_layers() + +integer :: ncid + +character(len=*), parameter :: routine = 'read_num_layers' + +ncid = nc_open_file_readonly(template_file) + +call nc_get_variable_size(ncid, 'Layer', nz) + +call nc_close_file(ncid) + +end subroutine read_num_layers + +!------------------------------------------------------------ +! ocean_geom are 2D state sized static data +! HK Do these arrays become too big in high res cases? +subroutine read_ocean_geometry() + +integer :: ncid + +character(len=*), parameter :: routine = 'read_ocean_geometry' + +! Need nx, ny +if ( .not. module_initialized ) call static_init_model + +ncid = nc_open_file_readonly(ocean_geometry) + +call nc_get_variable(ncid, 'D', basin_depth, routine) + +call nc_close_file(ncid) + +end subroutine read_ocean_geometry + +!=================================================================== +! End of model_mod +!=================================================================== +end module model_mod + diff --git a/models/MARBL_state_estimation/readme.rst b/models/MARBL_state_estimation/readme.rst new file mode 100644 index 0000000000..40d5ce4be0 --- /dev/null +++ b/models/MARBL_state_estimation/readme.rst @@ -0,0 +1,5 @@ +MARBL_state_estimation +======================= + +.. attention:: + Add your model documentation here. diff --git a/models/MARBL_state_estimation/work/input.nml b/models/MARBL_state_estimation/work/input.nml new file mode 100644 index 0000000000..2eea5790a3 --- /dev/null +++ b/models/MARBL_state_estimation/work/input.nml @@ -0,0 +1,238 @@ +&perfect_model_obs_nml + read_input_state_from_file = .true., + single_file_in = .false., + input_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/RESTART/DART_perfect_model_obs/MOM.res.nc", + + write_output_state_to_file = .true., + single_file_out = .false., + output_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/RESTART/DART_perfect_model_obs/MOM.res.output.nc", + output_interval = 1, + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_seq_in_file_name = "obs_seq.in", + obs_seq_out_file_name = "obs_seq.out", + init_time_days = 0, + init_time_seconds = 0, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + trace_execution = .false., + output_timestamps = .false., + print_every_nth_obs = -1, + output_forward_op_errors = .false., + silence = .false., + / + +&filter_nml + single_file_in = .false., + input_state_files = '', + input_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/DART/ensemble_members.txt', + + stages_to_write = 'preassim', 'analysis', 'output', + + single_file_out = .false., + output_state_files = '', + output_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/DART/ensemble_members.txt', + output_interval = 1, + output_members = .true., + num_output_state_members = 80, + output_mean = .true., + output_sd = .true., + write_all_stages_at_end = .true., + + ens_size = 80, + num_groups = 1, + perturb_from_single_instance = .false., + perturbation_amplitude = 1e-2, + distributed_state = .true., + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_sequence_in_name ='/glade/u/home/rarmstrong/work/BATS_state_estimation_obsseq/BATS_state_estimation_147976.out', + obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/output/147976/obs_seq.final', + num_output_obs_members = 80, + init_time_days = -1, + init_time_seconds = -1, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + inf_flavor = 5, 0, + inf_initial_from_restart = .true., .false., + inf_sd_initial_from_restart = .true., .false., + inf_deterministic = .true., .true., + inf_initial = 1.0, 1.0, + inf_lower_bound = 0.0, 1.0, + inf_upper_bound = 100.0, 1000000.0, + inf_damping = 0.9, 1.0, + inf_sd_initial = 0.6, 0.0, + inf_sd_lower_bound = 0.6, 0.0, + inf_sd_max_change = 1.05, 1.05, + + trace_execution = .true., + output_timestamps = .false., + output_forward_op_errors = .false., + silence = .false., + / + +&fill_inflation_restart_nml + write_prior_inf = .true., + prior_inf_mean = 1.0, + prior_inf_sd = 0.6, + + write_post_inf = .false., + post_inf_mean = 1.00, + post_inf_sd = 0.6, + + input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/ensemble/member_0001/RESTART/MOM.res.nc', + single_file = .false., + verbose = .false. + / + + +&ensemble_manager_nml + / + +&assim_tools_nml + filter_kind = 1, + cutoff = 1000000.0 + sort_obs_inc = .false., + spread_restoration = .false., + sampling_error_correction = .false., + adaptive_localization_threshold = -1, + distribute_mean = .false. + output_localization_diagnostics = .false., + localization_diagnostics_file = 'localization_diagnostics', + print_every_nth_obs = 0 + / + +&cov_cutoff_nml + select_localization = 1 + / + +®_factor_nml + select_regression = 1, + input_reg_file = "time_mean_reg", + save_reg_diagnostics = .false., + reg_diagnostics_file = "reg_diagnostics" + / + +&obs_sequence_nml + write_binary_obs_sequence = .false. + / + +&obs_kind_nml + assimilate_these_obs_types = 'POLY_ELECTRODE_OXYGEN', + 'TITRATION_ALKALINITY', + 'CATALYTIC_CARBON', + 'UV_OXY_NITROGEN', + 'CFA_SILICATE', + 'CFA_PHOSPHATE', + 'CFA_NITRATE' + evaluate_these_obs_types = '' + / + +&model_nml + template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/ensemble/member_0001/RESTART/MOM.res.nc', + time_step_days = 1, + time_step_seconds = 0, + model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', + 'PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', + 'DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', + 'O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', + 'DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', + 'DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', + 'DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', + 'ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', + 'microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' + / + +&utilities_nml + TERMLEVEL = 1, + module_details = .false., + logfilename = 'dart_log.out', + nmlfilename = 'dart_log.nml', + write_nml = 'none' + / + +&preprocess_nml + input_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/default_quantities_mod.f90' + / + +&obs_sequence_tool_nml + filename_seq = 'obs_seq.one', 'obs_seq.two', + filename_out = 'obs_seq.processed', + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + print_only = .false., + gregorian_cal = .false. + / + +&obs_diag_nml + obs_sequence_name = '' + obs_sequence_list = 'obs_diag_files/obs_seq_list.txt' + first_bin_center = 2005, 2, 24, 0, 0, 0 + last_bin_center = 2006, 2, 22, 0, 0, 0 + bin_separation = 0, 0, 1, 0, 0, 0 + bin_width = 0, 0, 1, 0, 0, 0 + time_to_skip = 0, 0, 0, 0, 0, 0 + max_num_bins = 1000 + plevel = -888888.0 + hlevel = -1, -5, -10, -50, -100, -250, -500, -1000, -2000, -3000, -4000, -5000, -6000 + mlevel = -888888 + plevel_edges = -888888.0 + hlevel_edges = -888888.0 + mlevel_edges = -888888 + Nregions = 1 + lonlim1 = 0 + lonlim2 = 360 + latlim1 = -90 + latlim2 = 90 + reg_names = 'null' + trusted_obs = 'null' + create_rank_histogram = .true. + outliers_in_histogram = .false. + use_zero_error_obs = .false. + verbose = .false. + / + +&state_vector_io_nml + / + +&model_mod_check_nml + input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' + output_state_files = 'testing/model_mod_check_output/output.nc' + test1thru = 0, + run_tests = 1,2,3,4,5,6,7 + x_ind = 261 + loc_of_interest = 296.0, 31.0, -200.0 + quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_CARBON' + interp_test_dx = 0.02 + interp_test_xrange = 0.0, 1.0 + verbose = .true. + / + +&quality_control_nml + input_qc_threshold = 3.0, + outlier_threshold = 3.0, +/ + +&location_nml + / diff --git a/models/MARBL_state_estimation/work/output_mean.nc b/models/MARBL_state_estimation/work/output_mean.nc new file mode 100644 index 0000000000000000000000000000000000000000..62479604a15655cb2f94ee6cce37dd8c804e1bbf GIT binary patch literal 27140 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 Date: Thu, 21 Dec 2023 09:58:09 -0700 Subject: [PATCH 02/35] Added in the BATS data converter which was developed on the param_estimation branch. Also added in the observation codes for BATS variables, which were accidentally left out of the last commit. --- .../forward_operators/obs_def_ocean_mod.f90 | 8 + observations/obs_converters/BATS/.gitignore | 4 + observations/obs_converters/BATS/README.md | 2 + .../obs_converters/BATS/bats_to_obs.f90 | 433 ++++++++++++++++++ .../obs_converters/BATS/work/input.nml | 67 +++ .../obs_converters/BATS/work/quickbuild.sh | 40 ++ .../obs_converters/ocean_color/.gitignore | 1 + .../shell_scripts/submit_download.sh | 10 + 8 files changed, 565 insertions(+) create mode 100644 observations/obs_converters/BATS/.gitignore create mode 100644 observations/obs_converters/BATS/README.md create mode 100644 observations/obs_converters/BATS/bats_to_obs.f90 create mode 100644 observations/obs_converters/BATS/work/input.nml create mode 100755 observations/obs_converters/BATS/work/quickbuild.sh create mode 100644 observations/obs_converters/ocean_color/.gitignore create mode 100755 observations/obs_converters/ocean_color/shell_scripts/submit_download.sh diff --git a/observations/forward_operators/obs_def_ocean_mod.f90 b/observations/forward_operators/obs_def_ocean_mod.f90 index daf95fc0b3..cc60436583 100644 --- a/observations/forward_operators/obs_def_ocean_mod.f90 +++ b/observations/forward_operators/obs_def_ocean_mod.f90 @@ -70,6 +70,14 @@ ! FERRYBOX_SALINITY, QTY_SALINITY, COMMON_CODE ! FERRYBOX_TEMPERATURE, QTY_TEMPERATURE, COMMON_CODE ! OCEAN_COLOR, QTY_SURFACE_CHLOROPHYLL, COMMON_CODE +! BATS_OXYGEN, QTY_DISSOLVED_OXYGEN, COMMON_CODE +! BATS_ALKALINITY, QTY_ALKALINITY, COMMON_CODE +! BATS_ORGANIC_CARBON, QTY_DISSOLVED_ORGANIC_CARBON, COMMON_CODE +! BATS_INORGANIC_CARBON, QTY_DISSOLVED_INORGANIC_CARBON, COMMON_CODE +! BATS_NITROGEN, QTY_DISSOLVED_ORGANIC_NITROGEN, COMMON_CODE +! BATS_NITRATE, QTY_NITRATE_CONCENTRATION, COMMON_CODE +! BATS_SILICATE, QTY_DISSOLVED_INORGANIC_SIO3, COMMON_CODE +! BATS_PHOSPHATE, QTY_PHOSPHATE_CONCENTRATION, COMMON_CODE ! END DART PREPROCESS TYPE DEFINITIONS ! From Ibrahim - 19 May 2009 diff --git a/observations/obs_converters/BATS/.gitignore b/observations/obs_converters/BATS/.gitignore new file mode 100644 index 0000000000..805d166c9b --- /dev/null +++ b/observations/obs_converters/BATS/.gitignore @@ -0,0 +1,4 @@ +data/* +obs_seq_files/* +work/bats_to_obs + diff --git a/observations/obs_converters/BATS/README.md b/observations/obs_converters/BATS/README.md new file mode 100644 index 0000000000..658f4cecd3 --- /dev/null +++ b/observations/obs_converters/BATS/README.md @@ -0,0 +1,2 @@ +This folder contains files adapted from those in DART/observations/obs\_converters/text, for the purpose of converting data from the [Bermude Atlantic Time-Series Study](https://bats.bios.asu.edu/) (BATS) into a format readable by DART. + diff --git a/observations/obs_converters/BATS/bats_to_obs.f90 b/observations/obs_converters/BATS/bats_to_obs.f90 new file mode 100644 index 0000000000..d960104fb4 --- /dev/null +++ b/observations/obs_converters/BATS/bats_to_obs.f90 @@ -0,0 +1,433 @@ +! DART software - Copyright UCAR. This open source software is provided +! by UCAR, "as is", without charge, subject to all terms of use at +! http://www.image.ucar.edu/DAReS/DART/DART_download +! +! $Id$ + +! This file is meant to read a text file containing bottle data from the +! Bermuda Atlantic Time-Series Study (https://bats.bios.asu.edu/). + +program bats_to_obs + +use types_mod, only : r8, PI, DEG2RAD +use utilities_mod, only : initialize_utilities, finalize_utilities, & + open_file, close_file, & + find_namelist_in_file, check_namelist_read, & + error_handler, E_ERR, E_MSG, nmlfileunit, & + do_nml_file, do_nml_term +use time_manager_mod, only : time_type, set_calendar_type, set_date, & + operator(>=), increment_time, get_time, & + operator(-), NOLEAP, GREGORIAN, operator(+), & + print_date +use location_mod, only : VERTISHEIGHT, VERTISPRESSURE +use obs_sequence_mod, only : obs_sequence_type, obs_type, read_obs_seq, & + static_init_obs_sequence, init_obs, write_obs_seq, & + init_obs_sequence, get_num_obs, set_copy_meta_data, & + set_qc_meta_data, destroy_obs_sequence + +use obs_kind_mod, only : BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, & + BATS_NITRATE, BATS_PHOSPHATE, BATS_SILICATE + +implicit none + +integer, parameter :: NUM_SCALAR_OBS = 6 ! maximum number of scalar observation variables that will + ! be assimilated at each observation. + +! this array defines the order in which observations are read from the file +integer, parameter :: OTYPE_ORDERING(NUM_SCALAR_OBS) & + = (/BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, BATS_NITRATE, & + BATS_PHOSPHATE, BATS_SILICATE/) + +real(r8), parameter :: MIN_OBS_ERROR = 0.1_r8 + +! namelist variables, changeable at runtime +character(len=256) :: text_input_file, obs_out_dir +integer :: max_lines, read_starting_at_line, date_firstcol, hourminute_firstcol +integer :: lat_cols(2), lon_cols(2), vert_cols(2) +integer :: scalar_obs_cols(2, NUM_SCALAR_OBS) +real(r8) :: obs_uncertainties(NUM_SCALAR_OBS) +logical :: debug + +namelist /bats_to_obs_nml/ text_input_file, max_lines, read_starting_at_line, date_firstcol, & + hourminute_firstcol, lat_cols, lon_cols, vert_cols, scalar_obs_cols, & + obs_uncertainties, obs_out_dir, debug + +! local variables +character (len=294) :: input_line, obs_out_file +character (len=6) :: daystr + +integer :: oday, day_bin, day_bin_old, osec, rcio, iunit, otype, line_number, otype_index +integer :: year, month, day, hour, minute, second, hourminute_raw, date_raw +integer :: num_copies, num_qc, max_obs +integer :: num_processed(NUM_SCALAR_OBS) + +logical :: file_exist, first_obs, new_obs_seq + +real(r8) :: temp, terr, qc, wdir, wspeed, werr, obs_err +real(r8) :: lat, lon, vert, uwnd, uerr, vwnd, verr, ovalue +real(r8) :: running_sum(NUM_SCALAR_OBS), running_sqsum(NUM_SCALAR_OBS), & + maxvals(NUM_SCALAR_OBS), minvals(NUM_SCALAR_OBS) + +! the uncertainties corresponding to the observations above + +type(obs_sequence_type) :: obs_seq +type(obs_type) :: obs, prev_obs +type(time_type) :: ref_day0, time_obs, prev_time + + +! start of executable code + +call initialize_utilities('bats_to_obs') + +! Read the namelist entries +call find_namelist_in_file("input.nml", "bats_to_obs_nml", iunit) +read(iunit, nml = bats_to_obs_nml, iostat = rcio) +call check_namelist_read(iunit, rcio, "bats_to_obs_nml") + +! Record the namelist values used for the run +if (do_nml_file()) write(nmlfileunit, nml=bats_to_obs_nml) +if (do_nml_term()) write( * , nml=bats_to_obs_nml) + +! time setup +call set_calendar_type(GREGORIAN) + +! open input text file + +iunit = open_file(text_input_file, 'formatted', 'read') +if (debug) print *, 'opened input file ' // trim(text_input_file) + +max_obs = NUM_SCALAR_OBS*max_lines +num_copies = 1 +num_qc = 1 + +! call the initialization code, and initialize two empty observation types +call static_init_obs_sequence() +call init_obs(obs, num_copies, num_qc) +call init_obs(prev_obs, num_copies, num_qc) +first_obs = .true. + +! Set the DART data quality control. +qc = 0.0_r8 + +! used later to manage splitting of data into obs-sequence files +day_bin_old = 0 + +line_number = 0 ! counts the number of lines that have been read so far + +do otype_index = 1, NUM_SCALAR_OBS + running_sum(otype_index) = 0.0_r8 ! these arrays will be used to compute means, + running_sqsum(otype_index) = 0.0_r8 ! variances, mins, and max's of observation values. + num_processed(otype_index) = 0 + maxvals(otype_index) = 0.0_r8 + minvals(otype_index) = 100000.0_r8 +end do + +obsloop: do ! no end limit - have the loop break when input ends + ! read in entire text line into a buffer + read(iunit, "(A)", iostat=rcio) input_line + line_number = line_number + 1 + + if(line_number < read_starting_at_line) then + cycle obsloop + end if + + if (rcio /= 0) then + if (debug) print *, 'got bad read code from input file at line ',line_number,', rcio = ', rcio + exit obsloop + endif + + ! extracting the date when the observation was taken + + read(input_line(date_firstcol:(date_firstcol + 7)), *, iostat=rcio) date_raw + if(rcio /= 0) then + if(debug) print *, "got bad read code getting date at line ",line_number,", rcio = ",rcio + exit obsloop + + else if(date_raw == -999) then + cycle obsloop ! missing date + + end if + + read(input_line(date_firstcol:(date_firstcol + 3)), *, iostat=rcio) year + if(rcio /= 0) then + if(debug) print *, "got bad read code getting year at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + read(input_line((date_firstcol + 4):(date_firstcol + 5)), *, iostat=rcio) month + if(rcio /= 0) then + if(debug) print *, "got bad read code getting month at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + read(input_line((date_firstcol + 6):(date_firstcol + 7)), *, iostat=rcio) day + if(rcio /= 0) then + if(debug) print *, "got bad read code getting day at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + if((month == 02) .and. (day == 29)) then ! we do not assimilate data taken on leap days + cycle obsloop + end if + + ! extracting the time of day when the observation was taken + + read(input_line(hourminute_firstcol:(hourminute_firstcol + 3)), *, iostat=rcio) hourminute_raw + if(rcio /= 0) then + if(debug) print *, "got bad read code parsing raw hour-minute at line ",line_number,", rcio = ",rcio + exit obsloop + + else if(hourminute_raw == -999) then + cycle obsloop ! missing timestamp + + else if(hourminute_raw < 60) then + hour = 0 + + else + read(input_line(hourminute_firstcol:(hourminute_firstcol + 1)), *, iostat=rcio) hour + + if(rcio /= 0) then + if(debug) print *, "got bad read code getting hour at line ",line_number,", rcio = ",rcio + exit obsloop + + end if + end if + + read(input_line((hourminute_firstcol + 2):(hourminute_firstcol + 3)), *, iostat=rcio) minute + if(rcio /= 0) then + if(debug) print *, "got bad read code getting minute at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + ! extracting the observation location + + read(input_line(vert_cols(1):vert_cols(2)), *, iostat=rcio) vert + if(rcio /= 0) then + if(debug) print *, "got bad read code getting vert at line ",line_number,", rcio = ",rcio + exit obsloop + + else if(abs(vert + 999.0) < 1.0d-8) then + cycle obsloop ! missing vertical coordinate + + else + vert = -vert ! MOM6 depth coordinate becomes negative as you increase depth + end if + + ! extracting the observation values + + otype_loop : do otype_index = 1, NUM_SCALAR_OBS + read(input_line(scalar_obs_cols(1, otype_index):scalar_obs_cols(2, otype_index)), *, iostat=rcio) ovalue + + if(rcio /= 0) then + if(debug) print *, "got bad read code getting observation type ",otype_index," at line ",line_number,", rcio = ",rcio + exit obsloop + + else if(abs(ovalue + 999.0) < 1.0d-8) then + cycle otype_loop ! missing observation + + end if + + ! unit corrections from BATS to MARBL + if((OTYPE_ORDERING(otype_index) == BATS_ALKALINITY) .or. (OTYPE_ORDERING(otype_index) == BATS_INORGANIC_CARBON)) then + ovalue = ovalue*1.026 + end if + + time_obs = set_date(year, month, day, hours=hour, minutes=minute) + call get_time(time_obs, osec, days=oday) + + if(debug) then + call print_date(time_obs, "adding observation taken on") + print *, " \__ observation type: ",OTYPE_ORDERING(otype_index) + print *, " vert: ",vert + print *, " observation value: ",ovalue + end if + + num_processed(otype_index) = num_processed(otype_index) + 1 + running_sum(otype_index) = running_sum(otype_index) + ovalue + running_sqsum(otype_index) = running_sqsum(otype_index) + ovalue**2 + maxvals(otype_index) = max(maxvals(otype_index), ovalue) + minvals(otype_index) = min(minvals(otype_index), ovalue) + + ! determining which obs-sequence file to put this observation into + day_bin = oday + if(osec > 43200) day_bin = day_bin + 1 + new_obs_seq = (first_obs .or. (day_bin /= day_bin_old)) + day_bin_old = day_bin + + ! if necessary, saving the old observation sequence and beginning a new one. + if(new_obs_seq) then + ! dumping the observations so far into their own file + if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then + if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) + call write_obs_seq(obs_seq, obs_out_file) + call destroy_obs_sequence(obs_seq) + first_obs = .true. + endif + + write(daystr, "(I6)") day_bin + obs_out_file = trim(obs_out_dir)//"/BATS_"//daystr//".out" + + ! create a new, empty obs_seq file. + call init_obs_sequence(obs_seq, num_copies, num_qc, max_obs) + + ! the first one needs to contain the string 'observation' and the + ! second needs the string 'QC'. + call set_copy_meta_data(obs_seq, 1, 'observation') + call set_qc_meta_data(obs_seq, 1, 'Data QC') + end if + + obs_err = max(obs_uncertainties(otype_index)*ovalue, MIN_OBS_ERROR) + + call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + ovalue, OTYPE_ORDERING(otype_index), obs_err, & + oday, osec, qc, obs) + + call add_obs_to_seq(obs_seq, obs, time_obs, prev_obs, prev_time, first_obs) + end do otype_loop +end do obsloop + +! putting any remaining observations into an obs sequence file + +if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then + if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) + call write_obs_seq(obs_seq, obs_out_file) + call destroy_obs_sequence(obs_seq) +endif + +print *, "" +print *, "SUMMARY:" +print *, "" + +do otype_index = 1, NUM_SCALAR_OBS + print *, "observation type: ",OTYPE_ORDERING(otype_index) + print *, "\__ total observations: ",num_processed(otype_index) + print *, " mean: ",running_sum(otype_index)/num_processed(otype_index) + print *, " variance: ",running_sqsum(otype_index)/num_processed(otype_index) & + - (running_sum(otype_index)/num_processed(otype_index))**2 + print *, " maximum value: ",maxvals(otype_index) + print *, " minimum value: ",minvals(otype_index) + print *, "" +end do + +! end of main program +call finalize_utilities() + +contains + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! +! create_3d_obs - subroutine that is used to create an observation +! type from observation data. +! +! NOTE: assumes the code is using the threed_sphere locations module, +! that the observation has a single data value and a single +! qc value, and that this obs type has no additional required +! data (e.g. gps and radar obs need additional data per obs) +! +! inputs: +! lat - latitude of observation +! lon - longitude of observation +! vval - vertical coordinate +! vkind - kind of vertical coordinate (pressure, level, etc) +! obsv - observation value +! otype - observation type +! oerr - observation error +! day - gregorian day +! sec - gregorian second +! qc - quality control value +! outputs: +! obs - observation type +! +! created Oct. 2007 Ryan Torn, NCAR/MMM +! adapted for more generic use 11 Mar 2010, nancy collins, ncar/image +! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +subroutine create_3d_obs(lat, lon, vval, vkind, obsv, otype, oerr, day, sec, qc, obs) +use types_mod, only : r8 +use obs_def_mod, only : obs_def_type, set_obs_def_time, set_obs_def_type_of_obs, & + set_obs_def_error_variance, set_obs_def_location +use obs_sequence_mod, only : obs_type, set_obs_values, set_qc, set_obs_def +use time_manager_mod, only : time_type, set_time +use location_mod, only : set_location + + integer, intent(in) :: otype, vkind, day, sec + real(r8), intent(in) :: lat, lon, vval, obsv, oerr, qc + type(obs_type), intent(inout) :: obs + +real(r8) :: obs_val(1), qc_val(1) +type(obs_def_type) :: obs_def + +call set_obs_def_location(obs_def, set_location(lon, lat, vval, vkind)) +call set_obs_def_type_of_obs(obs_def, otype) +call set_obs_def_time(obs_def, set_time(sec, day)) +call set_obs_def_error_variance(obs_def, oerr * oerr) +call set_obs_def(obs, obs_def) + +obs_val(1) = obsv +call set_obs_values(obs, obs_val) +qc_val(1) = qc +call set_qc(obs, qc_val) + +end subroutine create_3d_obs + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! +! add_obs_to_seq -- adds an observation to a sequence. inserts if first +! obs, inserts with a prev obs to save searching if that's possible. +! +! seq - observation sequence to add obs to +! obs - observation, already filled in, ready to add +! obs_time - time of this observation, in dart time_type format +! prev_obs - the previous observation that was added to this sequence +! (will be updated by this routine) +! prev_time - the time of the previously added observation +! (will also be updated by this routine) +! first_obs - should be initialized to be .true., and then will be +! updated by this routine to be .false. after the first obs +! has been added to this sequence. +! +! created Mar 8, 2010 nancy collins, ncar/image +! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +subroutine add_obs_to_seq(seq, obs, obs_time, prev_obs, prev_time, first_obs) + use types_mod, only : r8 + use obs_sequence_mod, only : obs_sequence_type, obs_type, insert_obs_in_seq + use time_manager_mod, only : time_type, operator(>=) + + type(obs_sequence_type), intent(inout) :: seq + type(obs_type), intent(inout) :: obs, prev_obs + type(time_type), intent(in) :: obs_time + type(time_type), intent(inout) :: prev_time + logical, intent(inout) :: first_obs + +! insert(seq,obs) always works (i.e. it inserts the obs in +! proper time format) but it can be slow with a long file. +! supplying a previous observation that is older (or the same +! time) as the new one speeds up the searching a lot. + +if(first_obs) then ! for the first observation, no prev_obs + call insert_obs_in_seq(seq, obs) + first_obs = .false. +else + if(obs_time >= prev_time) then ! same time or later than previous obs + call insert_obs_in_seq(seq, obs, prev_obs) + else ! earlier, search from start of seq + call insert_obs_in_seq(seq, obs) + endif +endif + +! update for next time +prev_obs = obs +prev_time = obs_time + +end subroutine add_obs_to_seq + +end program bats_to_obs + +! +! $URL$ +! $Id$ +! $Revision$ +! $Date$ diff --git a/observations/obs_converters/BATS/work/input.nml b/observations/obs_converters/BATS/work/input.nml new file mode 100644 index 0000000000..43e1c6589f --- /dev/null +++ b/observations/obs_converters/BATS/work/input.nml @@ -0,0 +1,67 @@ + +&bats_to_obs_nml + text_input_file = "../data/bats_bottle.txt" + max_lines = 68000 ! upper bound on the number of lines in the file that record observations + read_starting_at_line = 61 + date_firstcol = 14 ! first column of the YYYYMMDD date code at each line + hourminute_firstcol = 35 ! first column of the HHMM time stamp at each line + lat_cols = 42, 47 ! first and last columns where latitude, longitude, and vertical are recorded + lon_cols = 51, 56 + vert_cols = 58, 63 + scalar_obs_cols = 102, 107, ! i^th row of this table should list the first and last + 126, 131, ! columns where the value of the i^th observation variable + 134, 139, ! is recorded. Ordering of observation variables is defined + 141, 147, ! by the OTYPE_ORDERING parameter in bats_to_obs.f90. + 158, 164, + 166, 172 + obs_uncertainties = 0.2, ! i^th entry of this list gives the uncertainty associated + 0.2, ! with the i^th observation variable. Ordering of observation + 0.2, ! variables is defined by the OTYPE_ORDERING parameter in + 0.2, ! bats_to_obs.f90. + 0.2, + 0.2, + obs_out_dir = '../obs_seq_files', + debug = .true. + / + +&preprocess_nml + input_obs_def_mod_file = '../../../../observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '../../../../observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '../../../../observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '../../../../assimilation_code/modules/observations/default_quantities_mod.f90', '../../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' + / + +&obs_kind_nml + assimilate_these_obs_types = 'BATS_OXYGEN', + 'BATS_INORGANIC_CARBON', + 'BATS_ALKALINITY', + 'BATS_NITRATE', + 'BATS_PHOSPHATE', + 'BATS_SILICATE' + / + +&location_nml + / + +&utilities_nml + module_details = .false. + / + +&obs_sequence_nml + write_binary_obs_sequence = .false. + / + +&obs_sequence_tool_nml + filename_seq = 'obs_seq.out' + filename_seq_list = '' + filename_out = 'obs_seq.copy' + print_only = .false. + gregorian_cal = .true. + first_obs_days = -1 + first_obs_seconds = -1 + last_obs_days = -1 + last_obs_seconds = -1 + / + diff --git a/observations/obs_converters/BATS/work/quickbuild.sh b/observations/obs_converters/BATS/work/quickbuild.sh new file mode 100755 index 0000000000..de837d121f --- /dev/null +++ b/observations/obs_converters/BATS/work/quickbuild.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# DART software - Copyright UCAR. This open source software is provided +# by UCAR, "as is", without charge, subject to all terms of use at +# http://www.image.ucar.edu/DAReS/DART/DART_download + +main() { + +export DART=$(git rev-parse --show-toplevel) +source "$DART"/build_templates/buildconvfunctions.sh + +CONVERTER=BATS +LOCATION=threed_sphere + + +programs=( +bats_to_obs +obs_sequence_tool +advance_time +) + +# build arguments +arguments "$@" + +# clean the directory +\rm -f -- *.o *.mod Makefile .cppdefs + +# build and run preprocess before making any other DART executables +buildpreprocess + +# build +buildconv + + +# clean up +\rm -f -- *.o *.mod + +} + +main "$@" diff --git a/observations/obs_converters/ocean_color/.gitignore b/observations/obs_converters/ocean_color/.gitignore new file mode 100644 index 0000000000..60baa9cb83 --- /dev/null +++ b/observations/obs_converters/ocean_color/.gitignore @@ -0,0 +1 @@ +data/* diff --git a/observations/obs_converters/ocean_color/shell_scripts/submit_download.sh b/observations/obs_converters/ocean_color/shell_scripts/submit_download.sh new file mode 100755 index 0000000000..cbda90d801 --- /dev/null +++ b/observations/obs_converters/ocean_color/shell_scripts/submit_download.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +#PBS -N nasa_chlora_download +#PBS -A p93300012 +#PBS -l select=1:ncpus=4:mpiprocs=1 +#PBS -l walltime=05:00:00 +#PBS -q casper +#PBS -m abe + +./get_ocdata.sh > download_stderr.txt 2> download_stdout.txt \ No newline at end of file From 59917c7075096a482eb28265c20a831846aa2b1f Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Thu, 21 Dec 2023 14:32:44 -0700 Subject: [PATCH 03/35] Modified bats_to_obs.f90 so that it can generate obs_seq files fit for parameter smoothing. --- .../obs_converters/BATS/bats_to_obs.f90 | 88 ++++++++++++++----- .../obs_converters/BATS/work/input.nml | 1 + 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/observations/obs_converters/BATS/bats_to_obs.f90 b/observations/obs_converters/BATS/bats_to_obs.f90 index d960104fb4..5d5d2c3860 100644 --- a/observations/obs_converters/BATS/bats_to_obs.f90 +++ b/observations/obs_converters/BATS/bats_to_obs.f90 @@ -46,33 +46,33 @@ program bats_to_obs integer :: lat_cols(2), lon_cols(2), vert_cols(2) integer :: scalar_obs_cols(2, NUM_SCALAR_OBS) real(r8) :: obs_uncertainties(NUM_SCALAR_OBS) -logical :: debug +logical :: smoothing_only, debug namelist /bats_to_obs_nml/ text_input_file, max_lines, read_starting_at_line, date_firstcol, & hourminute_firstcol, lat_cols, lon_cols, vert_cols, scalar_obs_cols, & - obs_uncertainties, obs_out_dir, debug + obs_uncertainties, obs_out_dir, smoothing_only, debug ! local variables character (len=294) :: input_line, obs_out_file character (len=6) :: daystr -integer :: oday, day_bin, day_bin_old, osec, rcio, iunit, otype, line_number, otype_index +integer :: oday, clim_oday, day_bin, day_bin_old, osec, rcio, iunit, otype, line_number, otype_index integer :: year, month, day, hour, minute, second, hourminute_raw, date_raw integer :: num_copies, num_qc, max_obs integer :: num_processed(NUM_SCALAR_OBS) -logical :: file_exist, first_obs, new_obs_seq +logical :: file_exist, first_obs, new_obs_seq +logical :: clim_first_obs(365) real(r8) :: temp, terr, qc, wdir, wspeed, werr, obs_err real(r8) :: lat, lon, vert, uwnd, uerr, vwnd, verr, ovalue real(r8) :: running_sum(NUM_SCALAR_OBS), running_sqsum(NUM_SCALAR_OBS), & maxvals(NUM_SCALAR_OBS), minvals(NUM_SCALAR_OBS) -! the uncertainties corresponding to the observations above - type(obs_sequence_type) :: obs_seq +type(obs_sequence_type) :: clim_obs_seq(365) type(obs_type) :: obs, prev_obs -type(time_type) :: ref_day0, time_obs, prev_time +type(time_type) :: ref_day0, time_obs, clim_time_obs, prev_time ! start of executable code @@ -122,6 +122,22 @@ program bats_to_obs minvals(otype_index) = 100000.0_r8 end do +! for smoothing mode, we initialize 365 obs-sequence files to represent a climatology with daily resolution +if(smoothing_only) then + ! create a new, empty obs_seq file for each day of the year + do day = 1, 365 + print *, "initiating obs_seq file for day ",(day - 1),"/364" + call init_obs_sequence(clim_obs_seq(day), num_copies, num_qc, max_obs) + + ! the first one needs to contain the string 'observation' and the + ! second needs the string 'QC'. + call set_copy_meta_data(clim_obs_seq(day), 1, 'observation') + call set_qc_meta_data(clim_obs_seq(day), 1, 'Data QC') + + clim_first_obs(day) = .true. + end do +end if + obsloop: do ! no end limit - have the loop break when input ends ! read in entire text line into a buffer read(iunit, "(A)", iostat=rcio) input_line @@ -242,6 +258,16 @@ program bats_to_obs print *, " observation value: ",ovalue end if + if(smoothing_only) then + ! for ensemble smoothing, each observation is considered to be a measurement + ! of the same climatological "year", which is arbitrarily labeled as year 1601 + ! (the first year in DART's internal calendar). Observations are given identical + ! hour/minute timestamps so as to avoid time-ordering errors in the obs-seq file. + + clim_time_obs = set_date(1601, month, day, hours=0, minutes=0) + call get_time(clim_time_obs, osec, days=clim_oday) + end if + num_processed(otype_index) = num_processed(otype_index) + 1 running_sum(otype_index) = running_sum(otype_index) + ovalue running_sqsum(otype_index) = running_sqsum(otype_index) + ovalue**2 @@ -255,7 +281,7 @@ program bats_to_obs day_bin_old = day_bin ! if necessary, saving the old observation sequence and beginning a new one. - if(new_obs_seq) then + if((.not. smoothing_only) .and. new_obs_seq) then ! dumping the observations so far into their own file if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) @@ -278,22 +304,22 @@ program bats_to_obs obs_err = max(obs_uncertainties(otype_index)*ovalue, MIN_OBS_ERROR) - call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & - ovalue, OTYPE_ORDERING(otype_index), obs_err, & - oday, osec, qc, obs) + if(smoothing_only) then + call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + ovalue, OTYPE_ORDERING(otype_index), obs_err, & + clim_oday, osec, qc, obs) + + call add_obs_to_seq(clim_obs_seq(clim_oday + 1), obs, time_obs, prev_obs, prev_time, clim_first_obs(clim_oday + 1)) + else + call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + ovalue, OTYPE_ORDERING(otype_index), obs_err, & + oday, osec, qc, obs) - call add_obs_to_seq(obs_seq, obs, time_obs, prev_obs, prev_time, first_obs) + call add_obs_to_seq(obs_seq, obs, time_obs, prev_obs, prev_time, first_obs) + end if end do otype_loop end do obsloop -! putting any remaining observations into an obs sequence file - -if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then - if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) - call write_obs_seq(obs_seq, obs_out_file) - call destroy_obs_sequence(obs_seq) -endif - print *, "" print *, "SUMMARY:" print *, "" @@ -309,6 +335,28 @@ program bats_to_obs print *, "" end do +if(smoothing_only) then + do day = 1, 365 + if ( (.not. clim_first_obs(day)) .and. (get_num_obs(clim_obs_seq(day)) > 0) ) then + print *, "writing obs_seq file for day ",(day - 1),", obs_count = ", get_num_obs(clim_obs_seq(day)) + + write(daystr, "(I0.3)") (day - 1) + obs_out_file = trim(obs_out_dir)//"/clim_BATS_"//trim(daystr)//".out" + + call write_obs_seq(clim_obs_seq(day), obs_out_file) + call destroy_obs_sequence(clim_obs_seq(day)) + endif + end do +else + ! putting any remaining observations into an obs sequence file + + if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then + if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) + call write_obs_seq(obs_seq, obs_out_file) + call destroy_obs_sequence(obs_seq) + end if +end if + ! end of main program call finalize_utilities() diff --git a/observations/obs_converters/BATS/work/input.nml b/observations/obs_converters/BATS/work/input.nml index 43e1c6589f..e0668764b5 100644 --- a/observations/obs_converters/BATS/work/input.nml +++ b/observations/obs_converters/BATS/work/input.nml @@ -21,6 +21,7 @@ 0.2, 0.2, obs_out_dir = '../obs_seq_files', + smoothing_only = .true., debug = .true. / From a8f0bdfb579eb404360fd0bc5325c93673ace527 Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Tue, 2 Jan 2024 08:27:20 -0700 Subject: [PATCH 04/35] Added QTY codes for a subset of MARBL biogeochemical parameters. --- .../observations/ocean_quantities_mod.f90 | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/assimilation_code/modules/observations/ocean_quantities_mod.f90 b/assimilation_code/modules/observations/ocean_quantities_mod.f90 index f53a0a6f7f..ec79f014f3 100644 --- a/assimilation_code/modules/observations/ocean_quantities_mod.f90 +++ b/assimilation_code/modules/observations/ocean_quantities_mod.f90 @@ -41,6 +41,34 @@ ! QTY_DISSOLVED_INORGANIC_SIO3 ! QTY_MESOZOOPLANKTON_CARBON ! QTY_MICROZOOPLANKTON_CARBON +! QTY_PARAM_AUTOTROPH1_KCO2 +! QTY_PARAM_AUTOTROPH1_KDOP +! QTY_PARAM_AUTOTROPH1_KFE +! QTY_PARAM_AUTOTROPH1_KNH4 +! QTY_PARAM_AUTOTROPH1_KNO3 +! QTY_PARAM_AUTOTROPH1_KPO4 +! QTY_PARAM_AUTOTROPH1_KSIO3 +! QTY_PARAM_AUTOTROPH2_KCO2 +! QTY_PARAM_AUTOTROPH2_KDOP +! QTY_PARAM_AUTOTROPH2_KFE +! QTY_PARAM_AUTOTROPH2_KNH4 +! QTY_PARAM_AUTOTROPH2_KNO3 +! QTY_PARAM_AUTOTROPH2_KPO4 +! QTY_PARAM_AUTOTROPH2_KSIO3 +! QTY_PARAM_AUTOTROPH3_KCO2 +! QTY_PARAM_AUTOTROPH3_KDOP +! QTY_PARAM_AUTOTROPH3_KFE +! QTY_PARAM_AUTOTROPH3_KNH4 +! QTY_PARAM_AUTOTROPH3_KNO3 +! QTY_PARAM_AUTOTROPH3_KPO4 +! QTY_PARAM_AUTOTROPH3_KSIO3 +! QTY_PARAM_AUTOTROPH4_KCO2 +! QTY_PARAM_AUTOTROPH4_KDOP +! QTY_PARAM_AUTOTROPH4_KFE +! QTY_PARAM_AUTOTROPH4_KNH4 +! QTY_PARAM_AUTOTROPH4_KNO3 +! QTY_PARAM_AUTOTROPH4_KPO4 +! QTY_PARAM_AUTOTROPH4_KSIO3 ! ! ! fixme - these units are hardcoded in obs_diag and shouldn't be ! QTY_U_WIND_COMPONENT From 372fb8921a556faca34ba893879c95811f7c89c3 Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Thu, 4 Jan 2024 14:58:59 -0700 Subject: [PATCH 05/35] Added a draft (untested) model interface for MARBL_param_estimation. --- .../observations/ocean_quantities_mod.f90 | 1 + models/MARBL_param_estimation/model_mod.f90 | 563 ++++++++++++++++++ models/MARBL_param_estimation/readme.rst | 5 + models/MARBL_param_estimation/work/input.nml | 241 ++++++++ .../work/output_mean.nc | Bin 0 -> 27140 bytes .../MARBL_param_estimation/work/output_sd.nc | Bin 0 -> 27128 bytes .../MARBL_param_estimation/work/quickbuild.sh | 59 ++ 7 files changed, 869 insertions(+) create mode 100644 models/MARBL_param_estimation/model_mod.f90 create mode 100644 models/MARBL_param_estimation/readme.rst create mode 100644 models/MARBL_param_estimation/work/input.nml create mode 100644 models/MARBL_param_estimation/work/output_mean.nc create mode 100644 models/MARBL_param_estimation/work/output_sd.nc create mode 100755 models/MARBL_param_estimation/work/quickbuild.sh diff --git a/assimilation_code/modules/observations/ocean_quantities_mod.f90 b/assimilation_code/modules/observations/ocean_quantities_mod.f90 index ec79f014f3..600feb00a5 100644 --- a/assimilation_code/modules/observations/ocean_quantities_mod.f90 +++ b/assimilation_code/modules/observations/ocean_quantities_mod.f90 @@ -38,6 +38,7 @@ ! QTY_DISSOLVED_INORGANIC_IRON ! QTY_SURFACE_CHLOROPHYLL ! QTY_LAYER_THICKNESS +! QTY_COLUMN_DEPTH ! QTY_DISSOLVED_INORGANIC_SIO3 ! QTY_MESOZOOPLANKTON_CARBON ! QTY_MICROZOOPLANKTON_CARBON diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 new file mode 100644 index 0000000000..b1a63cb3b7 --- /dev/null +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -0,0 +1,563 @@ +! DART software - Copyright UCAR. This open source software is provided +! by UCAR, "as is", without charge, subject to all terms of use at +! http://www.image.ucar.edu/DAReS/DART/DART_download +! + +module model_mod + +! This is a template showing the interfaces required for a model to be compliant +! with the DART data assimilation infrastructure. Do not change the arguments +! for the public routines. + +use types_mod, only : r8, i8, MISSING_R8, vtablenamelength + +use time_manager_mod, only : time_type, set_time + +use location_mod, only : location_type, get_close_type, & + loc_get_close_obs => get_close_obs, & + loc_get_close_state => get_close_state, & + set_location, set_location_missing, & + get_location, VERTISLEVEL + +use utilities_mod, only : register_module, error_handler, & + E_ERR, E_MSG, & + nmlfileunit, do_output, do_nml_file, do_nml_term, & + find_namelist_in_file, check_namelist_read, & + to_upper + +use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & + nc_add_global_creation_time, & + nc_begin_define_mode, nc_end_define_mode, & + NF90_MAX_NAME, nc_open_file_readonly, & + nc_get_variable, nc_get_variable_size, nc_close_file + +use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & + get_varid_from_kind, get_dart_vector_index + +use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & + QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & + QTY_COLUMN_DEPTH + +use distributed_state_mod, only: get_state + +use ensemble_manager_mod, only : ensemble_type + +! These routines are passed through from default_model_mod. +! To write model specific versions of these routines +! remove the routine from this use statement and add your code to +! this the file. +use default_model_mod, only : pert_model_copies, write_model_time, & + init_time => fail_init_time, & + init_conditions => fail_init_conditions, & + convert_vertical_obs, convert_vertical_state, adv_1step + +implicit none +private + +! routines required by DART code - will be called from filter and other +! DART executables. +public :: get_model_size, & + get_state_meta_data, & + model_interpolate, & + end_model, & + static_init_model, & + nc_write_model_atts, & + get_close_obs, & + get_close_state, & + pert_model_copies, & + convert_vertical_obs, & + convert_vertical_state, & + read_model_time, & + adv_1step, & + init_time, & + init_conditions, & + shortest_time_between_assimilations, & + write_model_time + + +character(len=256), parameter :: source = "model_mod.f90" +character(len=256), parameter :: ocean_geometry = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/baseline/ocean_geometry.nc" +logical :: module_initialized = .false. +integer :: state_dom_id ! used to access the state structure +integer :: param_dom_id ! used to access MARBL internal parameters +integer :: nfields ! number of fields in the state or parameter vector +integer :: nz ! the number of vertical layers +integer :: model_size +type(time_type) :: assimilation_time_step +real(r8), parameter :: geolon = 360 - 64.0 +real(r8), parameter :: geolat = 31.0 + +! parameters to be used in specifying the DART internal state +integer, parameter :: modelvar_table_height = 13 +integer, parameter :: modelvar_table_width = 5 +integer, parameter :: modelparams_table_height = 2 +integer, parameter :: modelparams_table_width = 5 + +! defining the variables that will be read from the namelist +character(len=256) :: template_file(2) +integer :: time_step_days +integer :: time_step_seconds +logical :: estimate_params +character(len=vtablenamelength) & + :: model_state_variables(modelvar_table_height * modelvar_table_width) +character(len=vtablenamelength) & + :: model_parameters(modelparams_table_height * modelparams_table_width) + +namelist /model_nml/ template_file, & + time_step_days, & + time_step_seconds, & + model_state_variables, & + estimate_params, & + model_parameters +contains + +!------------------------------------------------------------------ +! +! Called to do one time initialization of the model. As examples, +! might define information about the model size or model timestep. +! In models that require pre-computed static data, for instance +! spherical harmonic weights, these would also be computed here. + +subroutine static_init_model() + +integer :: iunit, io +character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width), & + param_table(modelparams_table_height, modelparams_table_width) +integer :: state_qty_list(modelvar_table_height), & + param_qty_list(modelparams_table_height) +real(r8):: state_clamp_vals(modelvar_table_height, 2), & + param_clamp_vals(modelparams_table_height, 2) +logical :: update_var_list(modelvar_table_height), & + update_param_list(modelparams_table_height) + +module_initialized = .true. + +! Print module information to log file and stdout. +call register_module(source) + +! Read values from the namelist + +call find_namelist_in_file("input.nml", "model_nml", iunit) +read(iunit, nml = model_nml, iostat = io) + +call check_namelist_read(iunit, io, "model_nml") + +! Record the namelist values used for the run +if (do_nml_file()) write(nmlfileunit, nml=model_nml) +if (do_nml_term()) write( * , nml=model_nml) + +! This time is both the minimum time you can ask the model to advance +! (for models that can be advanced by filter) and it sets the assimilation +! window. All observations within +/- 1/2 this interval from the current +! model time will be assimilated. If this is not settable at runtime +! feel free to hardcode it and remove from the namelist. +assimilation_time_step = set_time(time_step_seconds, & + time_step_days) + +! setting up the DART state vector +call verify_state_variables(model_state_variables, nfields, variable_table, & + state_qty_list, state_clamp_vals, update_var_list) + + state_dom_id = add_domain(template_file(1), nfields, & + var_names = variable_table(1:nfields, 1), & + kind_list = state_qty_list(1:nfields), & + clamp_vals = state_clamp_vals, & + update_list = update_var_list(1:nfields)) + +! setting up the DART parameter vector +if(estimate_params) then + call verify_state_variables(model_parameters, nfields, param_table, & + param_qty_list, param_clamp_vals, update_param_list) + + param_dom_id = add_domain(template_file(2), nfields, & + var_names = param_table(1:nfields, 1), & + kind_list = param_qty_list(1:nfields), & + clamp_vals = param_clamp_vals, & + update_list = update_param_list(1:nfields)) +end if + +call read_num_layers ! setting the value of nz +call read_ocean_geometry ! determining the basin depth + +end subroutine static_init_model + +!------------------------------------------------------------------ +! Reads the simulation length from a netCDF file. + +function read_model_time(filename) + +character(len=*), intent(in) :: filename +type(time_type) :: read_model_time + +integer :: ncid +character(len=*), parameter :: routine = 'read_model_time' +real(r8) :: days +integer :: clim_day + +ncid = nc_open_file_readonly(filename, routine) + +call nc_get_variable(ncid, 'Time', days, routine) + +call nc_close_file(ncid, routine) + +clim_day = int(days) + +read_model_time = set_time(0,clim_day) + +end function read_model_time + +!------------------------------------------------------------------ +! Returns the number of items in the state vector as an integer. + +function get_model_size() + +integer(i8) :: get_model_size + +if ( .not. module_initialized ) call static_init_model + +get_model_size = get_domain_size(state_dom_id) + get_domain_size(param_dom_id) + +end function get_model_size + +!------------------------------------------------------------------ +! Given a state handle, a location, and a state quantity, +! interpolates the state variable fields to that location and returns +! the values in expected_obs. The istatus variables should be returned as +! 0 unless there is some problem in computing the interpolation in +! which case a positive istatus should be returned. +! +! For applications in which only perfect model experiments +! with identity observations (i.e. only the value of a particular +! state variable is observed), this can be a NULL INTERFACE. + +subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus) + +type(ensemble_type), intent(in) :: state_handle +integer, intent(in) :: ens_size +type(location_type), intent(in) :: location +integer, intent(in) :: qty +real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values +integer, intent(out) :: istatus(ens_size) + +integer :: qty_id, depth_id, ens_index, depth_index, layer_index, layer_above, layer_below +real(8) :: requested_depth, theta +real(8) :: loc_temp(3), depths(nz), vals_above(ens_size), vals_below(ens_size) + +if ( .not. module_initialized ) call static_init_model + +! extracting the the depths at which climatological averages are available + +depth_id = get_varid_from_kind(state_dom_id, QTY_COLUMN_DEPTH) + +do layer_index = 1, nz + depth_index = get_dart_vector_index(layer_index, 1, 1, state_dom_id, depth_id) + depths(layer_index) = get_state(depth_index, state_handle) +end do + +! extracting the requested depth value from `location` + +loc_temp = get_location(location) +requested_depth = loc_temp(3) + +print *, "REQUESTED DEPTH = ",requested_depth + +! figuring out the nearest layers above and below the requested depth + +layer_above = 1 +layer_below = 1 + +do while(depths(layer_below) <= requested_depth) + layer_below = layer_below + 1 + layer_above = layer_below - 1 +end do + +! determining the ensemble values above and below the requested depth + +qty_id = get_varid_from_kind(state_dom_id, qty) + +qty_index = get_dart_vector_index(layer_above, 1, 1, state_dom_id, qty_id) +vals_above = get_state(qty_index, state_handle) + +qty_index = get_dart_vector_index(layer_below, 1, 1, state_dom_id, qty_id) +vals_above = get_state(qty_index, state_handle) + +! linear interpolation + +do ens_index = 1, ens_size + istatus(ens_index) = 0 + + theta = (depths(layer_below) - requested_depth)/(depths(layer_below) - depths(layer_above)) + expected_obs(ens_index) = theta*vals_above(ens_index) + (1 - theta)*vals_below(ens_index) +end do + +end subroutine model_interpolate + +!------------------------------------------------------------------ +! Returns the smallest increment in time that the model is capable +! of advancing the state in a given implementation, or the shortest +! time you want the model to advance between assimilations. + +function shortest_time_between_assimilations() + +type(time_type) :: shortest_time_between_assimilations + +if ( .not. module_initialized ) call static_init_model + +shortest_time_between_assimilations = assimilation_time_step + +end function shortest_time_between_assimilations + + + +!------------------------------------------------------------------ +! Given an integer index into the state vector, returns the +! associated location and optionally the physical quantity. + +subroutine get_state_meta_data(index_in, location, qty) + +integer(i8), intent(in) :: index_in +type(location_type), intent(out) :: location +integer, intent(out), optional :: qty + +real(r8) :: lat, lon +integer :: lon_index, lat_index, level, local_qty + +if ( .not. module_initialized ) call static_init_model + +call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) + +location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) + +if (present(qty)) then + qty = local_qty +endif + + +end subroutine get_state_meta_data + + +!------------------------------------------------------------------ +! Any model specific distance calcualtion can be done here +subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & + num_close, close_ind, dist, ens_handle) + +type(get_close_type), intent(in) :: gc ! handle to a get_close structure +integer, intent(in) :: base_type ! observation TYPE +type(location_type), intent(inout) :: base_loc ! location of interest +type(location_type), intent(inout) :: locs(:) ! obs locations +integer, intent(in) :: loc_qtys(:) ! QTYS for obs +integer, intent(in) :: loc_types(:) ! TYPES for obs +integer, intent(out) :: num_close ! how many are close +integer, intent(out) :: close_ind(:) ! incidies into the locs array +real(r8), optional, intent(out) :: dist(:) ! distances in radians +type(ensemble_type), optional, intent(in) :: ens_handle + +character(len=*), parameter :: routine = 'get_close_obs' + +call loc_get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & + num_close, close_ind, dist, ens_handle) + +end subroutine get_close_obs + + +!------------------------------------------------------------------ +! Any model specific distance calcualtion can be done here +subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & + num_close, close_ind, dist, ens_handle) + +type(get_close_type), intent(in) :: gc ! handle to a get_close structure +type(location_type), intent(inout) :: base_loc ! location of interest +integer, intent(in) :: base_type ! observation TYPE +type(location_type), intent(inout) :: locs(:) ! state locations +integer, intent(in) :: loc_qtys(:) ! QTYs for state +integer(i8), intent(in) :: loc_indx(:) ! indices into DART state vector +integer, intent(out) :: num_close ! how many are close +integer, intent(out) :: close_ind(:) ! indices into the locs array +real(r8), optional, intent(out) :: dist(:) ! distances in radians +type(ensemble_type), optional, intent(in) :: ens_handle + +character(len=*), parameter :: routine = 'get_close_state' + + +call loc_get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & + num_close, close_ind, dist, ens_handle) + + +end subroutine get_close_state + + +!------------------------------------------------------------------ +! Does any shutdown and clean-up needed for model. Can be a NULL +! INTERFACE if the model has no need to clean up storage, etc. + +subroutine end_model() + + +end subroutine end_model + + +!------------------------------------------------------------------ +! write any additional attributes to the output and diagnostic files + +subroutine nc_write_model_atts(ncid, domain_id) + +integer, intent(in) :: ncid ! netCDF file identifier +integer, intent(in) :: domain_id + +if ( .not. module_initialized ) call static_init_model + +! put file into define mode. + +call nc_begin_define_mode(ncid) + +call nc_add_global_creation_time(ncid) + +call nc_add_global_attribute(ncid, "model_source", source ) +call nc_add_global_attribute(ncid, "model", "template") + +call nc_end_define_mode(ncid) + +! Flush the buffer and leave netCDF file open +call nc_synchronize_file(ncid) + +end subroutine nc_write_model_atts + +!------------------------------------------------------------------ +! Verify that the namelist was filled in correctly, and check +! that there are valid entries for the dart_kind. +! Returns a table with columns: +! +! netcdf_variable_name ; dart_qty_string ; lowerbound ; upperbound ; update_string + +subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp_vals, update_var) + +character(len=*), intent(inout) :: state_variables(:) +integer, intent(out) :: ngood +character(len=*), intent(out) :: table(:,:) +integer, intent(out) :: qty_list(:) ! kind number +real(r8), intent(out) :: clamp_vals(:,:) +logical, intent(out) :: update_var(:) ! logical update + +integer :: nrows, i +character(len=NF90_MAX_NAME) :: varname, dartstr, lowerbound, upperbound, update +character(len=256) :: string1, string2 + +if ( .not. module_initialized ) call static_init_model + +nrows = size(table,1) + +ngood = 0 + +MyLoop : do i = 1, nrows + + varname = trim(state_variables(5*i -4)) + dartstr = trim(state_variables(5*i -3)) + lowerbound = trim(state_variables(5*i -2)) + upperbound = trim(state_variables(5*i -1)) + update = trim(state_variables(5*i )) + + call to_upper(update) + + table(i,1) = trim(varname) + table(i,2) = trim(dartstr) + table(i,3) = trim(lowerbound) + table(i,4) = trim(upperbound) + table(i,5) = trim(update) + + if ( table(i,1) == ' ' .and. table(i,2) == ' ' .and. table(i,3) == ' ' .and. table(i,4) == ' ' .and. table(i,5) == ' ') exit MyLoop ! Found end of list. + + if ( table(i,1) == ' ' .or. table(i,2) == ' ' .or. table(i,3) == ' ' .or. table(i,4) == ' ' .or. table(i,5) == ' ') then + string1 = 'model_nml:model_state_variables not fully specified' + call error_handler(E_ERR,'verify_state_variables',string1) + endif + + ! Make sure DART qty is valid + + qty_list(i) = get_index_for_quantity(dartstr) + if( qty_list(i) < 0 ) then + write(string1,'(''there is no obs_kind <'',a,''> in obs_kind_mod.f90'')') trim(dartstr) + call error_handler(E_ERR,'verify_state_variables',string1) + endif + + ! Make sure the update variable has a valid name + + select case (update) + case ('UPDATE') + update_var(i) = .true. + case ('NO_COPY_BACK') + update_var(i) = .false. + case default + write(string1,'(A)') 'only UPDATE or NO_COPY_BACK supported in model_state_variable namelist' + write(string2,'(6A)') 'you provided : ', trim(varname), ', ', trim(dartstr), ', ', trim(update) + call error_handler(E_ERR,'verify_state_variables',string1, text2=string2) + end select + + ! reading the clamp values + + if (table(i, 3) /= 'NA') then + read(table(i,3), '(d16.8)') clamp_vals(i,1) + else + clamp_vals(i,1) = MISSING_R8 + endif + + if (table(i,4) /= 'NA') then + read(table(i,4), '(d16.8)') clamp_vals(i,2) + else + clamp_vals(i,2) = MISSING_R8 + endif + + ngood = ngood + 1 +enddo MyLoop + + +end subroutine verify_state_variables + +!------------------------------------------------------------ +function on_v_grid(qty) + +integer, intent(in) :: qty +logical :: on_v_grid + +if (qty == QTY_V_CURRENT_COMPONENT) then + on_v_grid = .true. +else + on_v_grid = .false. +endif + +end function on_v_grid + +!---------------------------------------------------------- +function on_u_grid(qty) + +integer, intent(in) :: qty +logical :: on_u_grid + +if (qty == QTY_U_CURRENT_COMPONENT) then + on_u_grid = .true. +else + on_u_grid = .false. +endif + +end function on_u_grid + +!------------------------------------------------------------ +! Read number of vertical layers from mom6 template file +subroutine read_num_layers() + +integer :: ncid + +character(len=*), parameter :: routine = 'read_num_layers' + +ncid = nc_open_file_readonly(template_file(1)) + +call nc_get_variable_size(ncid, 'Depth', nz) + +call nc_close_file(ncid) + +end subroutine read_num_layers + +!=================================================================== +! End of model_mod +!=================================================================== +end module model_mod + diff --git a/models/MARBL_param_estimation/readme.rst b/models/MARBL_param_estimation/readme.rst new file mode 100644 index 0000000000..9119443802 --- /dev/null +++ b/models/MARBL_param_estimation/readme.rst @@ -0,0 +1,5 @@ +MARBL_joint_estimation +======================= + +.. attention:: + Add your model documentation here. diff --git a/models/MARBL_param_estimation/work/input.nml b/models/MARBL_param_estimation/work/input.nml new file mode 100644 index 0000000000..ac9e8fdba3 --- /dev/null +++ b/models/MARBL_param_estimation/work/input.nml @@ -0,0 +1,241 @@ +&perfect_model_obs_nml + read_input_state_from_file = .true., + single_file_in = .false., + input_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/RESTART/DART_perfect_model_obs/MOM.res.nc", + + write_output_state_to_file = .true., + single_file_out = .false., + output_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/RESTART/DART_perfect_model_obs/MOM.res.output.nc", + output_interval = 1, + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_seq_in_file_name = "obs_seq.in", + obs_seq_out_file_name = "obs_seq.out", + init_time_days = 0, + init_time_seconds = 0, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + trace_execution = .false., + output_timestamps = .false., + print_every_nth_obs = -1, + output_forward_op_errors = .false., + silence = .false., + / + +&filter_nml + single_file_in = .false., + input_state_files = '', + input_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_params.txt', + + stages_to_write = 'preassim', 'analysis', 'output', + + single_file_out = .false., + output_state_files = '', + output_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_params.txt', + output_interval = 1, + output_members = .true., + num_output_state_members = 80, + output_mean = .true., + output_sd = .true., + write_all_stages_at_end = .true., + + ens_size = 80, + num_groups = 1, + perturb_from_single_instance = .false., + perturbation_amplitude = 1e-2, + distributed_state = .true., + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_sequence_in_name ='/glade/work/rarmstrong/BATS_obsseq/BATS_147638.out', + obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/output/147638/obs_seq.final', + num_output_obs_members = 80, + init_time_days = -1, + init_time_seconds = -1, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + inf_flavor = 5, 0, + inf_initial_from_restart = .true., .false., + inf_sd_initial_from_restart = .true., .false., + inf_deterministic = .true., .true., + inf_initial = 1.0, 1.0, + inf_lower_bound = 0.0, 1.0, + inf_upper_bound = 100.0, 1000000.0, + inf_damping = 0.9, 1.0, + inf_sd_initial = 0.6, 0.0, + inf_sd_lower_bound = 0.6, 0.0, + inf_sd_max_change = 1.05, 1.05, + + trace_execution = .true., + output_timestamps = .false., + output_forward_op_errors = .false., + silence = .false., + / + +&fill_inflation_restart_nml + write_prior_inf = .true., + prior_inf_mean = 1.0, + prior_inf_sd = 0.6, + + write_post_inf = .false., + post_inf_mean = 1.00, + post_inf_sd = 0.6, + + input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/INPUT/marbl_params.nc', + single_file = .false., + verbose = .false. + / + + +&ensemble_manager_nml + / + +&assim_tools_nml + filter_kind = 1, + cutoff = 1000000.0 + sort_obs_inc = .false., + spread_restoration = .false., + sampling_error_correction = .false., + adaptive_localization_threshold = -1, + distribute_mean = .false. + output_localization_diagnostics = .false., + localization_diagnostics_file = 'localization_diagnostics', + print_every_nth_obs = 0 + / + +&cov_cutoff_nml + select_localization = 1 + / + +®_factor_nml + select_regression = 1, + input_reg_file = "time_mean_reg", + save_reg_diagnostics = .false., + reg_diagnostics_file = "reg_diagnostics" + / + +&obs_sequence_nml + write_binary_obs_sequence = .false. + / + +&obs_kind_nml + assimilate_these_obs_types = 'BATS_OXYGEN', + 'BATS_ALKALINITY', + 'BATS_INORGANIC_CARBON', + 'BATS_SILICATE', + 'BATS_PHOSPHATE', + 'BATS_NITRATE', + evaluate_these_obs_types = 'BATS_NITROGEN', + 'BATS_ORGANIC_CARBON' + / + +&model_nml + template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/params_000.nc', + time_step_days = 1, + time_step_seconds = 0, + model_state_variables = 'clim_NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'clim_SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', + 'clim_PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'clim_Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', + 'clim_DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', + 'clim_O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', + 'clim_DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', + 'clim_DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', + 'clim_DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', + 'clim_ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', + 'clim_microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'clim_mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'Depth ', 'QTY_COLUMN_DEPTH ', 'NA ', 'NA', 'NO_COPY_BACK' + estimate_params = .true. + model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE' + / + +&utilities_nml + TERMLEVEL = 1, + module_details = .false., + logfilename = 'dart_log.out', + nmlfilename = 'dart_log.nml', + write_nml = 'none' + / + +&preprocess_nml + input_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/default_quantities_mod.f90', '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/ocean_quantities_mod.f90' + / + +&obs_sequence_tool_nml + filename_seq = 'obs_seq.one', 'obs_seq.two', + filename_out = 'obs_seq.processed', + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + print_only = .false., + gregorian_cal = .false. + / + +&obs_diag_nml + obs_sequence_name = '' + obs_sequence_list = 'obs_seq_list.txt' + first_bin_center = 2005, 2, 24, 0, 0, 0 + last_bin_center = 2010, 2, 28, 0, 0, 0 + bin_separation = 0, 0, 1, 0, 0, 0 + bin_width = 0, 0, 1, 0, 0, 0 + time_to_skip = 0, 0, 0, 0, 0, 0 + max_num_bins = 1000 + plevel = -888888.0 + hlevel = -1, -5, -10, -50, -100, -250, -500, -1000, -2000, -3000, -4000, -5000, -6000 + mlevel = -888888 + plevel_edges = -888888.0 + hlevel_edges = -888888.0 + mlevel_edges = -888888 + Nregions = 1 + lonlim1 = 0 + lonlim2 = 360 + latlim1 = -90 + latlim2 = 90 + reg_names = 'null' + trusted_obs = 'null' + create_rank_histogram = .true. + outliers_in_histogram = .false. + use_zero_error_obs = .false. + verbose = .false. + / + +&state_vector_io_nml + / + +&model_mod_check_nml + input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' + output_state_files = 'testing/model_mod_check_output/output.nc' + test1thru = 0, + run_tests = 1,2,3,4,5,6,7 + x_ind = 261 + loc_of_interest = 1.11, 0.54, -500.0 + quantity_of_interest = 'BATS_NITROGEN' + interp_test_dx = 0.02 + interp_test_xrange = 0.0, 1.0 + verbose = .true. + / + +&quality_control_nml + input_qc_threshold = 3.0, + outlier_threshold = 3.0, +/ + +&location_nml + / diff --git a/models/MARBL_param_estimation/work/output_mean.nc b/models/MARBL_param_estimation/work/output_mean.nc new file mode 100644 index 0000000000000000000000000000000000000000..62479604a15655cb2f94ee6cce37dd8c804e1bbf GIT binary patch literal 27140 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 Date: Fri, 5 Jan 2024 11:52:20 -0700 Subject: [PATCH 06/35] model_mod_check now runs without crashing for MARBL_param_estimation. This required fixing a bug in direct_netcdf_mod, using a solution provided by Helen Kershaw. --- .../modules/io/direct_netcdf_mod.f90 | 21 ++++--- models/MARBL_joint_estimation/work/input.nml | 63 ++++++------------- models/MARBL_param_estimation/model_mod.f90 | 16 ++--- models/MARBL_param_estimation/readme.rst | 2 +- models/MARBL_param_estimation/work/input.nml | 12 ++-- .../MARBL_param_estimation/work/quickbuild.sh | 2 +- 6 files changed, 47 insertions(+), 69 deletions(-) diff --git a/assimilation_code/modules/io/direct_netcdf_mod.f90 b/assimilation_code/modules/io/direct_netcdf_mod.f90 index 9419e19c73..aea2d8dae3 100644 --- a/assimilation_code/modules/io/direct_netcdf_mod.f90 +++ b/assimilation_code/modules/io/direct_netcdf_mod.f90 @@ -93,7 +93,7 @@ module direct_netcdf_mod get_index_start, get_index_end , get_num_dims, & create_diagnostic_structure, & end_diagnostic_structure, & - has_unlimited_dim + has_unlimited_dim, get_io_dim_ids use io_filenames_mod, only : get_restart_filename, inherit_copy_units, & stage_metadata_type, get_file_description, & @@ -858,16 +858,17 @@ subroutine read_variables(ncfile_in, var_block, start_var, end_var, domain) counts(:) = 1 slice_start(:) = 1 ! default to read all dimensions start at 1 - - if (has_unlimited_dim(domain)) then + + ret = nf90_inquire(ncfile_in, unlimitedDimID=unlim_dimID) + call nc_check(ret, 'read_variables: nf90_inquire', 'unlimitedDimID') + + if (has_unlimited_dim(domain) .and. any(get_io_dim_ids(domain, i) == unlim_dimID )) then counts(num_dims) = 1 ! one slice of unlimited dimesion - counts(1:num_dims-1) = get_dim_lengths(domain, i) ! the state + counts(1:get_num_dims(domain, i)) = get_dim_lengths(domain, i) ! the state ! read latest time slice - hack to get started with tiegcm ! not sure if it will always be the last time slice - ret = nf90_inquire(ncfile_in, unlimitedDimID=unlim_dimID) - call nc_check(ret, 'read_variables: nf90_inquire', 'unlimitedDimID') if (unlim_dimID /= -1) then ! unlimited dimension exists ret = nf90_inquire_dimension(ncfile_in, unlim_dimID, len=slice_start(num_dims)) @@ -1588,15 +1589,17 @@ subroutine write_variables(ncid, var_block, start_var, end_var, domain, & slice_start(:) = 1 ! default to read all dimensions starting at 1 counts(:) = 1 - if (has_unlimited_dim(domain)) then + ret = nf90_inquire(ncid, unlimitedDimID=unlim_dimID) + call nc_check(ret, 'read_variables: nf90_inquire', 'unlimitedDimID') + + if (has_unlimited_dim(domain) .and. any(get_io_dim_ids(domain, i) == unlim_dimID )) then counts(num_dims) = 1 ! one slice of unlimited dimesion counts(1:get_num_dims(domain, i)) = get_dim_lengths(domain, i) ! write the latest time slice - HK hack to get started with tiegcm ! not sure if it will always be the last time slice - ret = nf90_inquire(ncid, unlimitedDimID=unlim_dimID) - call nc_check(ret, 'write_variables: nf90_inquire', 'unlimitedDimID') + if (unlim_dimID /= -1) then ! unlimited dimension exists ret = nf90_inquire_dimension(ncid, unlim_dimID, len=slice_start(num_dims)) call nc_check(ret, 'write_variables: nf90_inquire dimension', 'unlimitedDim length') diff --git a/models/MARBL_joint_estimation/work/input.nml b/models/MARBL_joint_estimation/work/input.nml index 1e534465c3..0c16ebb8d8 100644 --- a/models/MARBL_joint_estimation/work/input.nml +++ b/models/MARBL_joint_estimation/work/input.nml @@ -45,7 +45,7 @@ write_all_stages_at_end = .true., ens_size = 80, - num_groups = 2, + num_groups = 1, perturb_from_single_instance = .false., perturbation_amplitude = 1e-2, distributed_state = .true., @@ -53,8 +53,8 @@ async = 0, adv_ens_command = "./advance_model.csh", - obs_sequence_in_name ='/glade/u/home/rarmstrong/work/BATS_joint_estimation_obsseq/BATS_joint_estimation_147612.out', - obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/output/147612/obs_seq.final', + obs_sequence_in_name ='/glade/u/home/rarmstrong/work/DART/observations/obs_converters/BATS/obs_seq_files/BATS_149468.out', + obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/output/149468/obs_seq.final', num_output_obs_members = 80, init_time_days = -1, init_time_seconds = -1, @@ -128,18 +128,19 @@ / &obs_kind_nml - assimilate_these_obs_types = 'POLY_ELECTRODE_OXYGEN', - 'TITRATION_ALKALINITY', - 'CATALYTIC_CARBON', - 'UV_OXY_NITROGEN', - 'CFA_SILICATE', - 'CFA_PHOSPHATE', - 'CFA_NITRATE' - evaluate_these_obs_types = '' + assimilate_these_obs_types = '' + evaluate_these_obs_types = 'BATS_OXYGEN', + 'BATS_ALKALINITY', + 'BATS_INORGANIC_CARBON', + 'BATS_SILICATE', + 'BATS_PHOSPHATE', + 'BATS_NITRATE', + 'BATS_ORGANIC_CARBON', + 'BATS_NITROGEN' / &model_nml - template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc', + template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc' time_step_days = 1, time_step_seconds = 0, model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', @@ -156,34 +157,8 @@ 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' estimate_params = .true. - model_parameters = 'autotroph_settings(1)%kCO2 ', 'QTY_PARAM_AUTOTROPH1_KCO2 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kFe ', 'QTY_PARAM_AUTOTROPH1_KFE ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kNO3 ', 'QTY_PARAM_AUTOTROPH1_KNO3 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kPO4 ', 'QTY_PARAM_AUTOTROPH1_KPO4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kSiO3', 'QTY_PARAM_AUTOTROPH1_KSIO3', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kCO2 ', 'QTY_PARAM_AUTOTROPH2_KCO2 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kDOP ', 'QTY_PARAM_AUTOTROPH2_KDOP ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kFe ', 'QTY_PARAM_AUTOTROPH2_KFE ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kNH4 ', 'QTY_PARAM_AUTOTROPH2_KNH4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kNO3 ', 'QTY_PARAM_AUTOTROPH2_KNO3 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kPO4 ', 'QTY_PARAM_AUTOTROPH2_KPO4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(2)%kSiO3', 'QTY_PARAM_AUTOTROPH2_KSIO3', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kCO2 ', 'QTY_PARAM_AUTOTROPH3_KCO2 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kDOP ', 'QTY_PARAM_AUTOTROPH3_KDOP ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kFe ', 'QTY_PARAM_AUTOTROPH3_KFE ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kNO3 ', 'QTY_PARAM_AUTOTROPH3_KNO3 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kNH4 ', 'QTY_PARAM_AUTOTROPH3_KNH4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kPO4 ', 'QTY_PARAM_AUTOTROPH3_KPO4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(3)%kSiO3', 'QTY_PARAM_AUTOTROPH3_KSIO3', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kCO2 ', 'QTY_PARAM_AUTOTROPH4_KCO2 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kDOP ', 'QTY_PARAM_AUTOTROPH4_KDOP ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kFe ', 'QTY_PARAM_AUTOTROPH4_KFE ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kNO3 ', 'QTY_PARAM_AUTOTROPH4_KNO3 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kNH4 ', 'QTY_PARAM_AUTOTROPH4_KNH4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kPO4 ', 'QTY_PARAM_AUTOTROPH4_KPO4 ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(4)%kSiO3', 'QTY_PARAM_AUTOTROPH4_KSIO3', '0.0', 'NA', 'UPDATE' + model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', + 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE' / &utilities_nml @@ -216,9 +191,9 @@ &obs_diag_nml obs_sequence_name = '' - obs_sequence_list = 'obs_diag_files/obs_seq_list.txt' + obs_sequence_list = 'obs_seq_list.txt' first_bin_center = 2005, 2, 24, 0, 0, 0 - last_bin_center = 2006, 2, 22, 0, 0, 0 + last_bin_center = 2010, 2, 28, 0, 0, 0 bin_separation = 0, 0, 1, 0, 0, 0 bin_width = 0, 0, 1, 0, 0, 0 time_to_skip = 0, 0, 0, 0, 0, 0 @@ -246,8 +221,8 @@ / &model_mod_check_nml - input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' - output_state_files = 'testing/model_mod_check_output/output.nc' + input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc' + output_state_files = 'output.nc' test1thru = 0, run_tests = 1,2,3,4,5,6,7 x_ind = 261 diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 index b1a63cb3b7..c859f94612 100644 --- a/models/MARBL_param_estimation/model_mod.f90 +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -177,7 +177,6 @@ subroutine static_init_model() end if call read_num_layers ! setting the value of nz -call read_ocean_geometry ! determining the basin depth end subroutine static_init_model @@ -239,9 +238,9 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values integer, intent(out) :: istatus(ens_size) -integer :: qty_id, depth_id, ens_index, depth_index, layer_index, layer_above, layer_below +integer :: qty_id, depth_id, qty_index, depth_index, ens_index, layer_index, layer_above, layer_below real(8) :: requested_depth, theta -real(8) :: loc_temp(3), depths(nz), vals_above(ens_size), vals_below(ens_size) +real(8) :: loc_temp(3), depths(nz), state_qty_tmp(ens_size), vals_above(ens_size), vals_below(ens_size) if ( .not. module_initialized ) call static_init_model @@ -250,8 +249,11 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs depth_id = get_varid_from_kind(state_dom_id, QTY_COLUMN_DEPTH) do layer_index = 1, nz - depth_index = get_dart_vector_index(layer_index, 1, 1, state_dom_id, depth_id) - depths(layer_index) = get_state(depth_index, state_handle) + depth_index = get_dart_vector_index(layer_index, 1, 1, state_dom_id, depth_id) + state_qty_tmp = get_state(depth_index, state_handle) + + ! gridpoint depths are identical across ensemble members, so we only need to query the first member. + depths(layer_index) = state_qty_tmp(1) end do ! extracting the requested depth value from `location` @@ -259,8 +261,6 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs loc_temp = get_location(location) requested_depth = loc_temp(3) -print *, "REQUESTED DEPTH = ",requested_depth - ! figuring out the nearest layers above and below the requested depth layer_above = 1 @@ -550,7 +550,7 @@ subroutine read_num_layers() ncid = nc_open_file_readonly(template_file(1)) -call nc_get_variable_size(ncid, 'Depth', nz) +call nc_get_variable_size(ncid, 'Layer', nz) call nc_close_file(ncid) diff --git a/models/MARBL_param_estimation/readme.rst b/models/MARBL_param_estimation/readme.rst index 9119443802..a42fe105d3 100644 --- a/models/MARBL_param_estimation/readme.rst +++ b/models/MARBL_param_estimation/readme.rst @@ -1,4 +1,4 @@ -MARBL_joint_estimation +MARBL_param_estimation ======================= .. attention:: diff --git a/models/MARBL_param_estimation/work/input.nml b/models/MARBL_param_estimation/work/input.nml index ac9e8fdba3..15ed3521dc 100644 --- a/models/MARBL_param_estimation/work/input.nml +++ b/models/MARBL_param_estimation/work/input.nml @@ -139,7 +139,7 @@ / &model_nml - template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/params_000.nc', + template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/clim_000.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/params_000.nc' time_step_days = 1, time_step_seconds = 0, model_state_variables = 'clim_NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', @@ -154,7 +154,7 @@ 'clim_ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', 'clim_microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', 'clim_mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'Depth ', 'QTY_COLUMN_DEPTH ', 'NA ', 'NA', 'NO_COPY_BACK' + 'Layer ', 'QTY_COLUMN_DEPTH ', 'NA ', 'NA', 'NO_COPY_BACK' estimate_params = .true. model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE' @@ -220,13 +220,13 @@ / &model_mod_check_nml - input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' - output_state_files = 'testing/model_mod_check_output/output.nc' + input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/clim_000.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/params_000.nc' + output_state_files = 'model_mod_check_output.nc' test1thru = 0, run_tests = 1,2,3,4,5,6,7 x_ind = 261 - loc_of_interest = 1.11, 0.54, -500.0 - quantity_of_interest = 'BATS_NITROGEN' + loc_of_interest = 1.11, 0.54, 500.0 + quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_NITROGEN' interp_test_dx = 0.02 interp_test_xrange = 0.0, 1.0 verbose = .true. diff --git a/models/MARBL_param_estimation/work/quickbuild.sh b/models/MARBL_param_estimation/work/quickbuild.sh index f96b002beb..58f81c13a2 100755 --- a/models/MARBL_param_estimation/work/quickbuild.sh +++ b/models/MARBL_param_estimation/work/quickbuild.sh @@ -9,7 +9,7 @@ main() { export DART=$(git rev-parse --show-toplevel) source "$DART"/build_templates/buildfunctions.sh -MODEL=MARBL_joint_estimation +MODEL=MARBL_param_estimation LOCATION=threed_sphere From a5f52b12f78efeda4488c92dffdb4c63fbb6b530 Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Fri, 5 Jan 2024 12:36:28 -0700 Subject: [PATCH 07/35] Interpolation function for MARBL_param_estimation now runs correctly. --- models/MARBL_param_estimation/model_mod.f90 | 51 ++++++++++++++++++-- models/MARBL_param_estimation/work/input.nml | 2 +- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 index c859f94612..5022c98c69 100644 --- a/models/MARBL_param_estimation/model_mod.f90 +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -86,6 +86,7 @@ module model_mod type(time_type) :: assimilation_time_step real(r8), parameter :: geolon = 360 - 64.0 real(r8), parameter :: geolat = 31.0 +logical, parameter :: debug_interpolation = .false. ! parameters to be used in specifying the DART internal state integer, parameter :: modelvar_table_height = 13 @@ -246,6 +247,15 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! extracting the the depths at which climatological averages are available +if (debug_interpolation) then + print *, "===================================================================" + print *, "model_interpolate" + print *, "===================================================================" + print *, "" + print *, "querying layer depths from climatology file..." + print *, "" +end if + depth_id = get_varid_from_kind(state_dom_id, QTY_COLUMN_DEPTH) do layer_index = 1, nz @@ -254,6 +264,10 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! gridpoint depths are identical across ensemble members, so we only need to query the first member. depths(layer_index) = state_qty_tmp(1) + + if (debug_interpolation) then + print *, " layer: ",layer_index,", depth: ",depths(layer_index) + end if end do ! extracting the requested depth value from `location` @@ -266,11 +280,27 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs layer_above = 1 layer_below = 1 -do while(depths(layer_below) <= requested_depth) +do while((depths(layer_below) <= requested_depth) .and. (layer_below < nz)) + ! This executes as long as the requested depth is not shallower than the shallowest + ! layer in the climatology. layer_below = layer_below + 1 layer_above = layer_below - 1 end do +if (depths(layer_below) <= requested_depth) then + ! this executes if the requested depth was deeper than the deepest layer in the climatology. + layer_above = layer_below +end if + +if (debug_interpolation) then + print *, "" + print *, "interpolating to depth: ",requested_depth + print *, "nearest layer index above: ",layer_above + print *, "nearest layer index below: ",layer_below + print *, "interpolating..." + print *, "" +end if + ! determining the ensemble values above and below the requested depth qty_id = get_varid_from_kind(state_dom_id, qty) @@ -279,15 +309,28 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs vals_above = get_state(qty_index, state_handle) qty_index = get_dart_vector_index(layer_below, 1, 1, state_dom_id, qty_id) -vals_above = get_state(qty_index, state_handle) +vals_below = get_state(qty_index, state_handle) ! linear interpolation do ens_index = 1, ens_size istatus(ens_index) = 0 - theta = (depths(layer_below) - requested_depth)/(depths(layer_below) - depths(layer_above)) - expected_obs(ens_index) = theta*vals_above(ens_index) + (1 - theta)*vals_below(ens_index) + if (layer_above < layer_below) then + theta = (depths(layer_below) - requested_depth)/(depths(layer_below) - depths(layer_above)) + expected_obs(ens_index) = theta*vals_above(ens_index) + (1 - theta)*vals_below(ens_index) + else + ! This block of code gets executed when the requested depth is shallower than the shallowest layer + ! in the climatology, or deeper than the deepest layer in the climatology. In either case, the "interpolated" + ! value is just the value of the closest layer, which is either the top layer or the bottom one. + + expected_obs(ens_index) = vals_below(ens_index) + end if + + if (debug_interpolation) then + print *, " member: ",ens_index,", value above: ",vals_above(ens_index),", & + value below: ",vals_below(ens_index),", interpolation: ",expected_obs(ens_index) + end if end do end subroutine model_interpolate diff --git a/models/MARBL_param_estimation/work/input.nml b/models/MARBL_param_estimation/work/input.nml index 15ed3521dc..8d3b76685b 100644 --- a/models/MARBL_param_estimation/work/input.nml +++ b/models/MARBL_param_estimation/work/input.nml @@ -225,7 +225,7 @@ test1thru = 0, run_tests = 1,2,3,4,5,6,7 x_ind = 261 - loc_of_interest = 1.11, 0.54, 500.0 + loc_of_interest = 1.11, 0.54, 45.0 quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_NITROGEN' interp_test_dx = 0.02 interp_test_xrange = 0.0, 1.0 From 6e3b47fec6a675be2380c991ef884b9d4fbaa526 Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Sat, 27 Jan 2024 19:27:45 -0700 Subject: [PATCH 08/35] Changed MARBL_param_estimation so that only one parameter is estimated. Split the BATS data converter into two separate converters, one for sequential state or state-parameter estimation, and another for pure parameter estimation. --- models/MARBL_joint_estimation/model_mod.f90 | 2 +- models/MARBL_joint_estimation/work/input.nml | 20 +- models/MARBL_param_estimation/model_mod.f90 | 11 +- .../MARBL_param_estimation/work/metadata.txt | 300 +++++++++++++++ .../work/model_mod_check_output.nc | Bin 0 -> 4128 bytes models/MARBL_param_estimation/work/null | Bin 0 -> 4096 bytes observations/obs_converters/BATS/.gitignore | 1 - .../obs_converters/BATS/bats_to_obs.f90 | 88 +---- .../obs_converters/BATS/work/input.nml | 9 +- .../obs_converters/BATS_clim/.gitignore | 4 + .../obs_converters/BATS_clim/README.md | 2 + .../BATS_clim/bats_climatology.py | 133 +++++++ .../BATS_clim/bats_to_clim_obs.f90 | 359 ++++++++++++++++++ .../obs_converters/BATS_clim/work/input.nml | 49 +++ .../BATS_clim/work/quickbuild.sh | 40 ++ 15 files changed, 926 insertions(+), 92 deletions(-) create mode 100644 models/MARBL_param_estimation/work/metadata.txt create mode 100644 models/MARBL_param_estimation/work/model_mod_check_output.nc create mode 100644 models/MARBL_param_estimation/work/null create mode 100644 observations/obs_converters/BATS_clim/.gitignore create mode 100644 observations/obs_converters/BATS_clim/README.md create mode 100644 observations/obs_converters/BATS_clim/bats_climatology.py create mode 100644 observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 create mode 100644 observations/obs_converters/BATS_clim/work/input.nml create mode 100755 observations/obs_converters/BATS_clim/work/quickbuild.sh diff --git a/models/MARBL_joint_estimation/model_mod.f90 b/models/MARBL_joint_estimation/model_mod.f90 index 49ccdff50c..e73c58c5be 100644 --- a/models/MARBL_joint_estimation/model_mod.f90 +++ b/models/MARBL_joint_estimation/model_mod.f90 @@ -91,7 +91,7 @@ module model_mod ! parameters to be used in specifying the DART internal state integer, parameter :: modelvar_table_height = 13 integer, parameter :: modelvar_table_width = 5 -integer, parameter :: modelparams_table_height = 2 +integer, parameter :: modelparams_table_height = 1 integer, parameter :: modelparams_table_width = 5 ! defining the variables that will be read from the namelist diff --git a/models/MARBL_joint_estimation/work/input.nml b/models/MARBL_joint_estimation/work/input.nml index 0c16ebb8d8..bbdf1a7cb8 100644 --- a/models/MARBL_joint_estimation/work/input.nml +++ b/models/MARBL_joint_estimation/work/input.nml @@ -90,7 +90,7 @@ post_inf_mean = 1.00, post_inf_sd = 0.6, - input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc', + input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/marbl_params.nc', single_file = .false., verbose = .false. / @@ -128,19 +128,18 @@ / &obs_kind_nml - assimilate_these_obs_types = '' - evaluate_these_obs_types = 'BATS_OXYGEN', + assimilate_these_obs_types = 'BATS_OXYGEN', 'BATS_ALKALINITY', 'BATS_INORGANIC_CARBON', 'BATS_SILICATE', 'BATS_PHOSPHATE', - 'BATS_NITRATE', - 'BATS_ORGANIC_CARBON', + 'BATS_NITRATE' + evaluate_these_obs_types = 'BATS_ORGANIC_CARBON', 'BATS_NITROGEN' / &model_nml - template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc' + template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/marbl_params.nc', time_step_days = 1, time_step_seconds = 0, model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', @@ -157,8 +156,7 @@ 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' estimate_params = .true. - model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE' + model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE' / &utilities_nml @@ -221,13 +219,13 @@ / &model_mod_check_nml - input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/INPUT/marbl_params.nc' - output_state_files = 'output.nc' + input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' + output_state_files = 'testing/model_mod_check_output/output.nc' test1thru = 0, run_tests = 1,2,3,4,5,6,7 x_ind = 261 loc_of_interest = 1.11, 0.54, -500.0 - quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_NITROGEN' + quantity_of_interest = 'BATS_NITROGEN' interp_test_dx = 0.02 interp_test_xrange = 0.0, 1.0 verbose = .true. diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 index 5022c98c69..a6ea060d38 100644 --- a/models/MARBL_param_estimation/model_mod.f90 +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -76,7 +76,6 @@ module model_mod character(len=256), parameter :: source = "model_mod.f90" -character(len=256), parameter :: ocean_geometry = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/baseline/ocean_geometry.nc" logical :: module_initialized = .false. integer :: state_dom_id ! used to access the state structure integer :: param_dom_id ! used to access MARBL internal parameters @@ -86,7 +85,7 @@ module model_mod type(time_type) :: assimilation_time_step real(r8), parameter :: geolon = 360 - 64.0 real(r8), parameter :: geolat = 31.0 -logical, parameter :: debug_interpolation = .false. +logical, parameter :: verbose_interpolation = .false. ! set this to .true. if you need to debug model_interpolate ! parameters to be used in specifying the DART internal state integer, parameter :: modelvar_table_height = 13 @@ -247,7 +246,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! extracting the the depths at which climatological averages are available -if (debug_interpolation) then +if (verbose_interpolation) then print *, "===================================================================" print *, "model_interpolate" print *, "===================================================================" @@ -265,7 +264,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! gridpoint depths are identical across ensemble members, so we only need to query the first member. depths(layer_index) = state_qty_tmp(1) - if (debug_interpolation) then + if (verbose_interpolation) then print *, " layer: ",layer_index,", depth: ",depths(layer_index) end if end do @@ -292,7 +291,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs layer_above = layer_below end if -if (debug_interpolation) then +if (verbose_interpolation) then print *, "" print *, "interpolating to depth: ",requested_depth print *, "nearest layer index above: ",layer_above @@ -327,7 +326,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs expected_obs(ens_index) = vals_below(ens_index) end if - if (debug_interpolation) then + if (verbose_interpolation) then print *, " member: ",ens_index,", value above: ",vals_above(ens_index),", & value below: ",vals_below(ens_index),", interpolation: ",expected_obs(ens_index) end if diff --git a/models/MARBL_param_estimation/work/metadata.txt b/models/MARBL_param_estimation/work/metadata.txt new file mode 100644 index 0000000000..eb412ad0f4 --- /dev/null +++ b/models/MARBL_param_estimation/work/metadata.txt @@ -0,0 +1,300 @@ + 1 i,j,k 1 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 2 i,j,k 2 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 3 i,j,k 3 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 4 i,j,k 4 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 5 i,j,k 5 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 6 i,j,k 6 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 7 i,j,k 7 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 8 i,j,k 8 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 9 i,j,k 9 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 10 i,j,k 10 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 11 i,j,k 11 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 12 i,j,k 12 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 13 i,j,k 13 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 14 i,j,k 14 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 15 i,j,k 15 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 16 i,j,k 16 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 17 i,j,k 17 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 18 i,j,k 18 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 19 i,j,k 19 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 20 i,j,k 20 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 21 i,j,k 1 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 22 i,j,k 2 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 23 i,j,k 3 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 24 i,j,k 4 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 25 i,j,k 5 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 26 i,j,k 6 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 27 i,j,k 7 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 28 i,j,k 8 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 29 i,j,k 9 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 30 i,j,k 10 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 31 i,j,k 11 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 32 i,j,k 12 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 33 i,j,k 13 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 34 i,j,k 14 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 35 i,j,k 15 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 36 i,j,k 16 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 37 i,j,k 17 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 38 i,j,k 18 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 39 i,j,k 19 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 40 i,j,k 20 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 41 i,j,k 1 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 42 i,j,k 2 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 43 i,j,k 3 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 44 i,j,k 4 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 45 i,j,k 5 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 46 i,j,k 6 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 47 i,j,k 7 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 48 i,j,k 8 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 49 i,j,k 9 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 50 i,j,k 10 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 51 i,j,k 11 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 52 i,j,k 12 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 53 i,j,k 13 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 54 i,j,k 14 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 55 i,j,k 15 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 56 i,j,k 16 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 57 i,j,k 17 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 58 i,j,k 18 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 59 i,j,k 19 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 60 i,j,k 20 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 61 i,j,k 1 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 62 i,j,k 2 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 63 i,j,k 3 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 64 i,j,k 4 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 65 i,j,k 5 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 66 i,j,k 6 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 67 i,j,k 7 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 68 i,j,k 8 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 69 i,j,k 9 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 70 i,j,k 10 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 71 i,j,k 11 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 72 i,j,k 12 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 73 i,j,k 13 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 74 i,j,k 14 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 75 i,j,k 15 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 76 i,j,k 16 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 77 i,j,k 17 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 78 i,j,k 18 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 79 i,j,k 19 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 80 i,j,k 20 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 81 i,j,k 1 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 82 i,j,k 2 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 83 i,j,k 3 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 84 i,j,k 4 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 85 i,j,k 5 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 86 i,j,k 6 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 87 i,j,k 7 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 88 i,j,k 8 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 89 i,j,k 9 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 90 i,j,k 10 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 91 i,j,k 11 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 92 i,j,k 12 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 93 i,j,k 13 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 94 i,j,k 14 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 95 i,j,k 15 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 96 i,j,k 16 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 97 i,j,k 17 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 98 i,j,k 18 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 99 i,j,k 19 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 100 i,j,k 20 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 101 i,j,k 1 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 102 i,j,k 2 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 103 i,j,k 3 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 104 i,j,k 4 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 105 i,j,k 5 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 106 i,j,k 6 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 107 i,j,k 7 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 108 i,j,k 8 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 109 i,j,k 9 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 110 i,j,k 10 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 111 i,j,k 11 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 112 i,j,k 12 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 113 i,j,k 13 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 114 i,j,k 14 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 115 i,j,k 15 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 116 i,j,k 16 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 117 i,j,k 17 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 118 i,j,k 18 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 119 i,j,k 19 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 120 i,j,k 20 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 121 i,j,k 1 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 122 i,j,k 2 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 123 i,j,k 3 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 124 i,j,k 4 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 125 i,j,k 5 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 126 i,j,k 6 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 127 i,j,k 7 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 128 i,j,k 8 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 129 i,j,k 9 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 130 i,j,k 10 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 131 i,j,k 11 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 132 i,j,k 12 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 133 i,j,k 13 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 134 i,j,k 14 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 135 i,j,k 15 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 136 i,j,k 16 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 137 i,j,k 17 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 138 i,j,k 18 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 139 i,j,k 19 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 140 i,j,k 20 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 141 i,j,k 1 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 142 i,j,k 2 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 143 i,j,k 3 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 144 i,j,k 4 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 145 i,j,k 5 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 146 i,j,k 6 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 147 i,j,k 7 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 148 i,j,k 8 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 149 i,j,k 9 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 150 i,j,k 10 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 151 i,j,k 11 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 152 i,j,k 12 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 153 i,j,k 13 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 154 i,j,k 14 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 155 i,j,k 15 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 156 i,j,k 16 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 157 i,j,k 17 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 158 i,j,k 18 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 159 i,j,k 19 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 160 i,j,k 20 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 161 i,j,k 1 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 162 i,j,k 2 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 163 i,j,k 3 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 164 i,j,k 4 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 165 i,j,k 5 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 166 i,j,k 6 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 167 i,j,k 7 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 168 i,j,k 8 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 169 i,j,k 9 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 170 i,j,k 10 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 171 i,j,k 11 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 172 i,j,k 12 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 173 i,j,k 13 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 174 i,j,k 14 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 175 i,j,k 15 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 176 i,j,k 16 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 177 i,j,k 17 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 178 i,j,k 18 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 179 i,j,k 19 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 180 i,j,k 20 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 181 i,j,k 1 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 182 i,j,k 2 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 183 i,j,k 3 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 184 i,j,k 4 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 185 i,j,k 5 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 186 i,j,k 6 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 187 i,j,k 7 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 188 i,j,k 8 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 189 i,j,k 9 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 190 i,j,k 10 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 191 i,j,k 11 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 192 i,j,k 12 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 193 i,j,k 13 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 194 i,j,k 14 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 195 i,j,k 15 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 196 i,j,k 16 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 197 i,j,k 17 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 198 i,j,k 18 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 199 i,j,k 19 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 200 i,j,k 20 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 201 i,j,k 1 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 202 i,j,k 2 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 203 i,j,k 3 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 204 i,j,k 4 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 205 i,j,k 5 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 206 i,j,k 6 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 207 i,j,k 7 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 208 i,j,k 8 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 209 i,j,k 9 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 210 i,j,k 10 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 211 i,j,k 11 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 212 i,j,k 12 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 213 i,j,k 13 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 214 i,j,k 14 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 215 i,j,k 15 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 216 i,j,k 16 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 217 i,j,k 17 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 218 i,j,k 18 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 219 i,j,k 19 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 220 i,j,k 20 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 221 i,j,k 1 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 222 i,j,k 2 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 223 i,j,k 3 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 224 i,j,k 4 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 225 i,j,k 5 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 226 i,j,k 6 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 227 i,j,k 7 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 228 i,j,k 8 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 229 i,j,k 9 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 230 i,j,k 10 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 231 i,j,k 11 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 232 i,j,k 12 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 233 i,j,k 13 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 234 i,j,k 14 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 235 i,j,k 15 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 236 i,j,k 16 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 237 i,j,k 17 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 238 i,j,k 18 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 239 i,j,k 19 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 240 i,j,k 20 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 241 i,j,k 1 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 242 i,j,k 2 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 243 i,j,k 3 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 244 i,j,k 4 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 245 i,j,k 5 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 246 i,j,k 6 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 247 i,j,k 7 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 248 i,j,k 8 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 249 i,j,k 9 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 250 i,j,k 10 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 251 i,j,k 11 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 252 i,j,k 12 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 253 i,j,k 13 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 254 i,j,k 14 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 255 i,j,k 15 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 256 i,j,k 16 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 257 i,j,k 17 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 258 i,j,k 18 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 259 i,j,k 19 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 260 i,j,k 20 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 261 i,j,k 1 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 262 i,j,k 2 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 263 i,j,k 3 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 264 i,j,k 4 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 265 i,j,k 5 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 266 i,j,k 6 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 267 i,j,k 7 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 268 i,j,k 8 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 269 i,j,k 9 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 270 i,j,k 10 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 271 i,j,k 11 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 272 i,j,k 12 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 273 i,j,k 13 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 274 i,j,k 14 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 275 i,j,k 15 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 276 i,j,k 16 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 277 i,j,k 17 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 278 i,j,k 18 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 279 i,j,k 19 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 280 i,j,k 20 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 281 i,j,k 1 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 282 i,j,k 2 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 283 i,j,k 3 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 284 i,j,k 4 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 285 i,j,k 5 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 286 i,j,k 6 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 287 i,j,k 7 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 288 i,j,k 8 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 289 i,j,k 9 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 290 i,j,k 10 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 291 i,j,k 11 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 292 i,j,k 12 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 293 i,j,k 13 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 294 i,j,k 14 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 295 i,j,k 15 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 296 i,j,k 16 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 297 i,j,k 17 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 298 i,j,k 18 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 299 i,j,k 19 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level + 300 i,j,k 20 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level diff --git a/models/MARBL_param_estimation/work/model_mod_check_output.nc b/models/MARBL_param_estimation/work/model_mod_check_output.nc new file mode 100644 index 0000000000000000000000000000000000000000..6ed3d551660f86f737c07b7f78bea81806822918 GIT binary patch literal 4128 zcmcJR30TZqAIC>h(<-D!xc-%0Wt!qf%kM-RQBl?xW6Vq$&8C^sc;mWVm-nh{S=$#W zl(JVNp)Ap+w?Rs|FHf%+-H1x+y5~P*yO*c;d0y^$o-?2GKj(YC|KB-tmj6sQ4-E>1 z(hp}{oXPTlIV>4B1Q&2J##vL!6L3{e6pB9P5S$IzAzYS}ClWF_Ea|&OvhRc?I1zK_ z5^ipUmls*^_a~eQ2AyF~&}|9&6vCE4&>aYSJGG&{K*ZtlnG#WG2%EGaJq*-!_}3?Y)&BaPvaV*em9>b5Hs0) zo`C7&tC|_|-BScSAv27{$MZ)JbQ}7|L|735Rygs#jU36l-ki@Fc3p##<$s^;v^ z3$?F4cX1yBb)S!mukV-!hU514_dMxMX7aA@kFyS6Bn)B-S?@mr$aOpt-#t7IL4Fw! zqCi5rnoFo|XhI_W@I63fv-n&ghedu$kbN|TA|ZLI4+s_Vq!L`fNmb8b$;d}?9a70k z3dM*9g~Lmx;}RyDV`do)g=PVn-zRlJAua2kw%7MiIHaS*?$iJ%)E2Mlba#M)rXaIL#MkUCy>Oo%IIJmL16RK^Jm)y6shHjfnmhxfSkZ#%YBMX1Lhm3!H z_OC^Owa8*ZWOUnpQ)I`9DY`guBC_{r+n2fh5n_Z#&D`a#g&5h>;sa$y$nL4Q*8X7> zD9aWQWPHjStFkoKRD!Z%nQ11A4$2zME%puJpsbG-pV_eolx=!Br><{=XJdmmzPvge zT8*Vz_D9}AYt->{DoTj=NAxe><8)Y|3%$8H=pXUMb*hn2x4aM=@qN`ykhi9@G|FEr`1i zK;Fy{S3JOU9p4<{E_PLRYd1q&X@AOT*aC6a%Nf?0Mi5secUV1>32}FnKSUOf!0jhO z3mD5;t9@|Ca$*1X~TQBFy2ITl`E7j|)L3ZHSlursH}-Uap2X{=4;MNJ;5vNnGqSE z*E;R8{N3%C{@zrF5X`co;PJKK6<*Q#+OYw=)}Mp}FLl6c$vs!&>V; z<~Zf+?gY$PHA3&Xn8CJVpLb#I={!620%oP1gINhmzNIm#aZ3+MR`}@HF?3P#{nW09 z3^7XS7v<4=`3y>#xaE3@NVMk2; zL1Tkrq^P6|^&iqcCA4@A)D2v8xN6i3xHM}~$Fa-zK^`--+CAn5*l8a-G;6JqW66Y8 z$*ocP$RN&e6B(aDoM}j2z$Hw2!D;7E%taNJPAf4Z%FRda#yqNgd-MY4lk-X4ahScX zBV;={(a}4jW8uc*oXx=xwM*A*GS08ldL=<=?^)l?b^C8nL*A4zmDgw z3dp&!%XCGW1LSV$jvfrVA=j;is_4yz!$+lW#N{htH({>V6vYGH&?P~p$@{=5ZC-*9rA1pi z1)0^Ov;?}zcg!H>5_V(N95z3>1x^(50lJn)~U+Y_R32wzN4l~;{$3+CNj zhcXN?+XlrO=Rws8uOOC#bx~od1Cb5-<{1RVa3Zc>l}TOGir{R TSWR0>C1%&gxBVdMnzV41!<+^#v;V^&NgH3UpBB zQENu#!mff~7Ht!CE-nN&QY)5lbG1pe?N2B$7(f(3zfaEoKCDAG?Din+K)3>(E`+Pl zd+QFI&2=I&R_dyV=@>d=&c*P%oUVl~uWn<`r<{fn`7m>>7oyD%A6Y6h!K6xck=u)n zb6@Go3@ZadmC(U`NOaDn0+cRgy|ndr0X+rJj6Lfbj>WT($U?-1DPiIyWw&s(TFa1E%=sG0=RxM!sbN^g=+VU=9V?Nrlo}zl%o9GocbrPl{@4N-LW6dZnZ((Lu5C zgrCxq@H8lhsXsR^fBpXR{oBs7wP#;{eExFL-gu_g@#w#v0ndPEz%$?(@C 0) ) then if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) @@ -304,22 +278,22 @@ program bats_to_obs obs_err = max(obs_uncertainties(otype_index)*ovalue, MIN_OBS_ERROR) - if(smoothing_only) then - call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & - ovalue, OTYPE_ORDERING(otype_index), obs_err, & - clim_oday, osec, qc, obs) - - call add_obs_to_seq(clim_obs_seq(clim_oday + 1), obs, time_obs, prev_obs, prev_time, clim_first_obs(clim_oday + 1)) - else - call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & - ovalue, OTYPE_ORDERING(otype_index), obs_err, & - oday, osec, qc, obs) + call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + ovalue, OTYPE_ORDERING(otype_index), obs_err, & + oday, osec, qc, obs) - call add_obs_to_seq(obs_seq, obs, time_obs, prev_obs, prev_time, first_obs) - end if + call add_obs_to_seq(obs_seq, obs, time_obs, prev_obs, prev_time, first_obs) end do otype_loop end do obsloop +! putting any remaining observations into an obs sequence file + +if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then + if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) + call write_obs_seq(obs_seq, obs_out_file) + call destroy_obs_sequence(obs_seq) +endif + print *, "" print *, "SUMMARY:" print *, "" @@ -335,28 +309,6 @@ program bats_to_obs print *, "" end do -if(smoothing_only) then - do day = 1, 365 - if ( (.not. clim_first_obs(day)) .and. (get_num_obs(clim_obs_seq(day)) > 0) ) then - print *, "writing obs_seq file for day ",(day - 1),", obs_count = ", get_num_obs(clim_obs_seq(day)) - - write(daystr, "(I0.3)") (day - 1) - obs_out_file = trim(obs_out_dir)//"/clim_BATS_"//trim(daystr)//".out" - - call write_obs_seq(clim_obs_seq(day), obs_out_file) - call destroy_obs_sequence(clim_obs_seq(day)) - endif - end do -else - ! putting any remaining observations into an obs sequence file - - if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then - if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) - call write_obs_seq(obs_seq, obs_out_file) - call destroy_obs_sequence(obs_seq) - end if -end if - ! end of main program call finalize_utilities() diff --git a/observations/obs_converters/BATS/work/input.nml b/observations/obs_converters/BATS/work/input.nml index e0668764b5..6a20cd5e8e 100644 --- a/observations/obs_converters/BATS/work/input.nml +++ b/observations/obs_converters/BATS/work/input.nml @@ -15,13 +15,12 @@ 158, 164, 166, 172 obs_uncertainties = 0.2, ! i^th entry of this list gives the uncertainty associated - 0.2, ! with the i^th observation variable. Ordering of observation + 0.2, ! with the i^th observation variable. Ordering of observation 0.2, ! variables is defined by the OTYPE_ORDERING parameter in - 0.2, ! bats_to_obs.f90. - 0.2, - 0.2, + 0.2, ! bats_to_obs.f90. + 0.2, ! + 0.2 obs_out_dir = '../obs_seq_files', - smoothing_only = .true., debug = .true. / diff --git a/observations/obs_converters/BATS_clim/.gitignore b/observations/obs_converters/BATS_clim/.gitignore new file mode 100644 index 0000000000..8c479c6be6 --- /dev/null +++ b/observations/obs_converters/BATS_clim/.gitignore @@ -0,0 +1,4 @@ +data/* +obs_seq_files/* +work/bats_to_clim_obs +*.pdf diff --git a/observations/obs_converters/BATS_clim/README.md b/observations/obs_converters/BATS_clim/README.md new file mode 100644 index 0000000000..658f4cecd3 --- /dev/null +++ b/observations/obs_converters/BATS_clim/README.md @@ -0,0 +1,2 @@ +This folder contains files adapted from those in DART/observations/obs\_converters/text, for the purpose of converting data from the [Bermude Atlantic Time-Series Study](https://bats.bios.asu.edu/) (BATS) into a format readable by DART. + diff --git a/observations/obs_converters/BATS_clim/bats_climatology.py b/observations/obs_converters/BATS_clim/bats_climatology.py new file mode 100644 index 0000000000..255762d648 --- /dev/null +++ b/observations/obs_converters/BATS_clim/bats_climatology.py @@ -0,0 +1,133 @@ +import numpy as np +import matplotlib.pyplot as plt + +################################################################# +####################### SCRIPT PARAMETERS ####################### +################################################################# + +# input and output datafiles +input_file = 'data/bats_bottle.txt' +output_file = 'data/bats_climatology.txt' + +first_data_line = 61 # file is read starting at this line (so that header information is ignored) +month_columns = [18, 19] # first and last columns in the data file containing month values +depth_columns = [58, 63] # first and last columns in the data file containing depth values +num_obs_types = 6 # number of variables being read from the datafile +max_num_data = 16660 # upper bound on the number of data points to be processed + +# first and last columns in the data file containing values for each variable +obs_val_columns = [[102, 107], # O2 + [126, 131], # CO2 + [134, 139], # Alk + [141, 147], # NO31 + [158, 164], # PO41 + [166, 172]] # Si1 + +# layer interface depths for data in prog_z.nc output file from MARBL +marbl_depths = [0, 5, 15, 25, 40, 62.5, 87.5, 112.5, 137.5, 175, 225, 275, 350, 450, + 550, 650, 750, 850, 950, 1050, 1150, 1250, 1350, 1450, 1625, 1875, 2250, + 2750, 3250, 3750, 4250, 4750, 5250, 5750, 6250] + +# set to 'True' in order to produce a histogram of BATS observation vs depth for each month +plot_sample_hist = True + +# human-readable names of the variables being read from the file +obs_names = ["O2", "CO2", "Alk", "NO31", "PO41", "Si1"] + +################################################################# +####################### MAIN PROGRAM ############################ +################################################################# + +clim_means = np.zeros((num_obs_types, 12, len(marbl_depths))) +sq_means = np.zeros((num_obs_types, 12, len(marbl_depths))) +sample_counts = np.zeros((num_obs_types, 12, len(marbl_depths)), dtype=int) + +bats_data = open(input_file, "r") +line_number = 0 + +for line in bats_data.readlines(): + line_number += 1 + + if(line_number < first_data_line): + continue + + if(line_number % 1000 == 0): + print("processing line",line_number,"...") + + # extracting the depth and month where this observation was taken + + depth_val = float(line[depth_columns[0]-1:depth_columns[1]]) + month_index = int(line[month_columns[0]-1:month_columns[1]]) - 1 + + # assigning this observation to one of the MARBL layers + + depth_index = len(marbl_depths) - 1 + + while((depth_val < marbl_depths[depth_index]) and (depth_index > 0)): + depth_index -= 1 + + # adding this observation into the climatology + + for obs_type_index in range(num_obs_types): + obs_val = float(line[obs_val_columns[obs_type_index][0]-1:obs_val_columns[obs_type_index][1]]) + + if(abs(obs_val + 999.0) > 1e-8): # this filters out 'missing' values + prev_mean = clim_means[obs_type_index, month_index, depth_index] + prev_sqmean = sq_means[obs_type_index, month_index, depth_index] + prev_samples = sample_counts[obs_type_index, month_index, depth_index] + + new_mean = (prev_samples*prev_mean + obs_val)/(prev_samples + 1) + new_sqmean = (prev_samples*prev_sqmean + obs_val**2)/(prev_samples + 1) + + clim_means[obs_type_index, month_index, depth_index] = new_mean + sq_means[obs_type_index, month_index, depth_index] = new_sqmean + + sample_counts[obs_type_index, month_index, depth_index] += 1 + +bats_data.close() + +# writing the climatology into a CSV file that will be readable by a DART data converter + +clim_file = open(output_file, "w") + +for month_index in range(12): + for obs_type_index in range(num_obs_types): + for depth_index in range(len(marbl_depths)): + samples = sample_counts[obs_type_index, month_index, depth_index] + + if(samples > 0): + depth = marbl_depths[depth_index] + mean = clim_means[obs_type_index, month_index, depth_index] + sq_mean = sq_means[obs_type_index, month_index, depth_index] + + variability = (sq_mean - mean**2)/samples + obs_error = (.1*mean)**2 + uq = variability + obs_error + + clim_file.write(str(month_index+1)+","+str(obs_type_index+1)+","+str(depth)+","+str(mean)+","+str(uq)+"\n") + +clim_file.close() + +if(plot_sample_hist): + month_plot = 12*[None] + month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] + + fig = plt.figure(figsize = (6, 70)) + + for month_index in range(12): + month_plot[month_index] = fig.add_subplot(12, 1, month_index + 1) + month_plot[month_index].set_xlabel("Depth (meters)") + month_plot[month_index].set_xscale("log") + month_plot[month_index].set_ylabel("Number of Data Points ("+month_names[month_index]+")") + month_plot[month_index].set_yscale("log") + + (month_index == 0) and month_plot[month_index].set_title("Depth Distribution of BATS Data") + + for obs_type_index in range(num_obs_types): + month_plot[month_index].plot(marbl_depths, sample_counts[obs_type_index, month_index, :], marker = "o", markerfacecolor = "none", label = obs_names[obs_type_index]) + + month_plot[month_index].legend() + + plt.legend() + plt.savefig("bats_depth_hist.pdf") + plt.close(fig) diff --git a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 new file mode 100644 index 0000000000..104fb5f2bd --- /dev/null +++ b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 @@ -0,0 +1,359 @@ +! DART software - Copyright UCAR. This open source software is provided +! by UCAR, "as is", without charge, subject to all terms of use at +! http://www.image.ucar.edu/DAReS/DART/DART_download +! +! $Id$ + +! This file is meant to read a text file containing bottle data from the +! Bermuda Atlantic Time-Series Study (https://bats.bios.asu.edu/), which +! is converted to climatological estimates with monthly resolution. + +program bats_to_clim_obs + +use types_mod, only : r8, PI, DEG2RAD +use utilities_mod, only : initialize_utilities, finalize_utilities, & + open_file, close_file, & + find_namelist_in_file, check_namelist_read, & + error_handler, E_ERR, E_MSG, nmlfileunit, & + do_nml_file, do_nml_term +use time_manager_mod, only : time_type, set_calendar_type, set_date, & + operator(>=), increment_time, get_time, & + operator(-), NOLEAP, GREGORIAN, operator(+), & + print_date +use location_mod, only : VERTISHEIGHT, VERTISPRESSURE +use obs_sequence_mod, only : obs_sequence_type, obs_type, read_obs_seq, & + static_init_obs_sequence, init_obs, write_obs_seq, & + init_obs_sequence, get_num_obs, set_copy_meta_data, & + set_qc_meta_data, destroy_obs_sequence + +use obs_kind_mod, only : BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, & + BATS_NITRATE, BATS_PHOSPHATE, BATS_SILICATE + +implicit none + +integer, parameter :: NUM_SCALAR_OBS = 6 ! maximum number of scalar observation variables that will + ! be assimilated at each observation. + +! this array defines the order in which observations are read from the file +integer, parameter :: OTYPE_ORDERING(NUM_SCALAR_OBS) & + = (/BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, BATS_NITRATE, & + BATS_PHOSPHATE, BATS_SILICATE/) + +real(r8), parameter :: MIN_OBS_ERROR = 0.1_r8 + +! namelist variables, changeable at runtime +character(len=256) :: text_input_file, obs_out_dir +integer :: max_lines +logical :: debug + +namelist /bats_to_clim_obs_nml/ text_input_file, max_lines, obs_out_dir, debug + +! local variables +character (len=294) :: input_line, obs_out_file +character (len=6) :: month_str + +integer :: oday, osec, rcio, iunit, otype, char_index, comma_index, line_number, otype_index, & + year, month, month_old, day, hour, minute, second, num_copies, num_qc, max_obs +integer :: comma_locs(4) + +logical :: first_obs, new_obs_seq + +real(r8) :: qc, obs_err +real(r8) :: lat, lon, vert, ovalue + +! the uncertainties corresponding to the observations above + +type(obs_sequence_type) :: obs_seq +type(obs_type) :: obs, prev_obs +type(time_type) :: time_obs, prev_time + + +! start of executable code + +call initialize_utilities('bats_to_clim_obs') + +! Read the namelist entries +call find_namelist_in_file("input.nml", "bats_to_clim_obs_nml", iunit) +read(iunit, nml = bats_to_clim_obs_nml, iostat = rcio) +call check_namelist_read(iunit, rcio, "bats_to_clim_obs_nml") + +! Record the namelist values used for the run +if (do_nml_file()) write(nmlfileunit, nml=bats_to_clim_obs_nml) +if (do_nml_term()) write( * , nml=bats_to_clim_obs_nml) + +! time setup +call set_calendar_type(GREGORIAN) + +! open input text file + +iunit = open_file(text_input_file, 'formatted', 'read') +if (debug) print *, 'opened input file ' // trim(text_input_file) + +max_obs = NUM_SCALAR_OBS*max_lines +num_copies = 1 +num_qc = 1 + +! call the initialization code, and initialize two empty observation types +call static_init_obs_sequence() +call init_obs(obs, num_copies, num_qc) +call init_obs(prev_obs, num_copies, num_qc) +first_obs = .true. + +! Set the DART data quality control. +qc = 0.0_r8 + +! used later to manage splitting of data into obs-sequence files +month_old = 0 + +line_number = 0 ! counts the number of lines that have been read so far + +obsloop: do ! no end limit - have the loop break when input ends + ! read in entire text line into a buffer + read(iunit, "(A)", iostat=rcio) input_line + line_number = line_number + 1 + + if (rcio /= 0) then + if (debug) print *, 'got bad read code from input file at line ',line_number,', rcio = ', rcio + exit obsloop + endif + + ! finding the locations of commas within the string + + comma_index = 0 + char_index = 0 + + do while(comma_index < 4) + char_index = char_index + 1 + + if(input_line(char_index:char_index) == ',') then + comma_index = comma_index + 1 + comma_locs(comma_index) = char_index + end if + end do + + ! reading the month value of this line + + read(input_line(1:(comma_locs(1) - 1)), *, iostat=rcio) month + if(rcio /= 0) then + if(debug) print *, "got bad read code getting month at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + ! reading the observation type + + read(input_line((comma_locs(1) + 1):(comma_locs(2) - 1)), *, iostat=rcio) otype_index + if(rcio /= 0) then + if(debug) print *, "got bad read code getting obs type at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + ! reading the observation depth + + read(input_line((comma_locs(2) + 1):(comma_locs(3) - 1)), *, iostat=rcio) vert + if(rcio /= 0) then + if(debug) print *, "got bad read code getting vert at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + ! reading the observtaion value + + read(input_line((comma_locs(3) + 1):(comma_locs(4) - 1)), *, iostat=rcio) ovalue + if(rcio /= 0) then + if(debug) print *, "got bad read code getting observation value at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + ! reading the observtaion uncertainty + + read(input_line((comma_locs(4) + 1):len(input_line)), *, iostat=rcio) obs_err + if(rcio /= 0) then + if(debug) print *, "got bad read code getting observation uncertainty at line ",line_number,", rcio = ",rcio + exit obsloop + end if + + ! unit corrections from BATS to MARBL + + if((OTYPE_ORDERING(otype_index) == BATS_ALKALINITY) .or. (OTYPE_ORDERING(otype_index) == BATS_INORGANIC_CARBON)) then + ovalue = ovalue*1.026 + obs_err = obs_err*1.026**2 ! check with Helen to make sure that obs_err is a variance and not a standard deviation + end if + + if(debug) then + print *, "adding climatological mean for month ",month + print *, " \__ type: ",OTYPE_ORDERING(otype_index) + print *, " vert: ",vert + print *, " value: ",ovalue + print *, " uncertainty: ",obs_err + end if + + ! For ensemble smoothing, each observation is considered to be a measurement + ! of the same climatological "year", which is arbitrarily labeled as year 1601 + ! (the first year in DART's internal calendar). Observations are given identical + ! day/hour/minute timestamps to avoid time-ordering errors in the obs-seq file. + + time_obs = set_date(1601, month, 1, hours=0, minutes=0) + call get_time(time_obs, osec, days=oday) + + new_obs_seq = (first_obs .or. (month /= month_old)) + month_old = month + + ! if necessary, saving the old observation sequence and beginning a new one. + if(new_obs_seq) then + ! dumping the observations so far into their own file + if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then + if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) + call write_obs_seq(obs_seq, obs_out_file) + call destroy_obs_sequence(obs_seq) + first_obs = .true. + endif + + write(month_str, "(I0.2)") month + obs_out_file = trim(obs_out_dir)//"/BATS_clim_"//trim(month_str)//".out" + + ! create a new, empty obs_seq file. + call init_obs_sequence(obs_seq, num_copies, num_qc, max_obs) + + ! the first one needs to contain the string 'observation' and the + ! second needs the string 'QC'. + call set_copy_meta_data(obs_seq, 1, 'observation') + call set_qc_meta_data(obs_seq, 1, 'Data QC') + end if + + ! adding the observation + call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + ovalue, OTYPE_ORDERING(otype_index), obs_err, & + oday, osec, qc, obs) + + call add_obs_to_seq(obs_seq, obs, time_obs, prev_obs, prev_time, first_obs) +end do obsloop + +! putting any remaining observations into an obs sequence file + +if ( (.not. first_obs) .and. (get_num_obs(obs_seq) > 0) ) then + if (debug) print *, 'writing obs_seq, obs_count = ', get_num_obs(obs_seq) + call write_obs_seq(obs_seq, obs_out_file) + call destroy_obs_sequence(obs_seq) +endif + +! end of main program +call finalize_utilities() + +contains + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! +! create_3d_obs - subroutine that is used to create an observation +! type from observation data. +! +! NOTE: assumes the code is using the threed_sphere locations module, +! that the observation has a single data value and a single +! qc value, and that this obs type has no additional required +! data (e.g. gps and radar obs need additional data per obs) +! +! inputs: +! lat - latitude of observation +! lon - longitude of observation +! vval - vertical coordinate +! vkind - kind of vertical coordinate (pressure, level, etc) +! obsv - observation value +! otype - observation type +! oerr - observation error +! day - gregorian day +! sec - gregorian second +! qc - quality control value +! outputs: +! obs - observation type +! +! created Oct. 2007 Ryan Torn, NCAR/MMM +! adapted for more generic use 11 Mar 2010, nancy collins, ncar/image +! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +subroutine create_3d_obs(lat, lon, vval, vkind, obsv, otype, oerr, day, sec, qc, obs) +use types_mod, only : r8 +use obs_def_mod, only : obs_def_type, set_obs_def_time, set_obs_def_type_of_obs, & + set_obs_def_error_variance, set_obs_def_location +use obs_sequence_mod, only : obs_type, set_obs_values, set_qc, set_obs_def +use time_manager_mod, only : time_type, set_time +use location_mod, only : set_location + + integer, intent(in) :: otype, vkind, day, sec + real(r8), intent(in) :: lat, lon, vval, obsv, oerr, qc + type(obs_type), intent(inout) :: obs + +real(r8) :: obs_val(1), qc_val(1) +type(obs_def_type) :: obs_def + +call set_obs_def_location(obs_def, set_location(lon, lat, vval, vkind)) +call set_obs_def_type_of_obs(obs_def, otype) +call set_obs_def_time(obs_def, set_time(sec, day)) +call set_obs_def_error_variance(obs_def, oerr * oerr) +call set_obs_def(obs, obs_def) + +obs_val(1) = obsv +call set_obs_values(obs, obs_val) +qc_val(1) = qc +call set_qc(obs, qc_val) + +end subroutine create_3d_obs + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! +! add_obs_to_seq -- adds an observation to a sequence. inserts if first +! obs, inserts with a prev obs to save searching if that's possible. +! +! seq - observation sequence to add obs to +! obs - observation, already filled in, ready to add +! obs_time - time of this observation, in dart time_type format +! prev_obs - the previous observation that was added to this sequence +! (will be updated by this routine) +! prev_time - the time of the previously added observation +! (will also be updated by this routine) +! first_obs - should be initialized to be .true., and then will be +! updated by this routine to be .false. after the first obs +! has been added to this sequence. +! +! created Mar 8, 2010 nancy collins, ncar/image +! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +subroutine add_obs_to_seq(seq, obs, obs_time, prev_obs, prev_time, first_obs) + use types_mod, only : r8 + use obs_sequence_mod, only : obs_sequence_type, obs_type, insert_obs_in_seq + use time_manager_mod, only : time_type, operator(>=) + + type(obs_sequence_type), intent(inout) :: seq + type(obs_type), intent(inout) :: obs, prev_obs + type(time_type), intent(in) :: obs_time + type(time_type), intent(inout) :: prev_time + logical, intent(inout) :: first_obs + +! insert(seq,obs) always works (i.e. it inserts the obs in +! proper time format) but it can be slow with a long file. +! supplying a previous observation that is older (or the same +! time) as the new one speeds up the searching a lot. + +if(first_obs) then ! for the first observation, no prev_obs + call insert_obs_in_seq(seq, obs) + first_obs = .false. +else + if(obs_time >= prev_time) then ! same time or later than previous obs + call insert_obs_in_seq(seq, obs, prev_obs) + else ! earlier, search from start of seq + call insert_obs_in_seq(seq, obs) + endif +endif + +! update for next time +prev_obs = obs +prev_time = obs_time + +end subroutine add_obs_to_seq + +end program bats_to_clim_obs + +! +! $URL$ +! $Id$ +! $Revision$ +! $Date$ diff --git a/observations/obs_converters/BATS_clim/work/input.nml b/observations/obs_converters/BATS_clim/work/input.nml new file mode 100644 index 0000000000..f178f80273 --- /dev/null +++ b/observations/obs_converters/BATS_clim/work/input.nml @@ -0,0 +1,49 @@ + +&bats_to_clim_obs_nml + text_input_file = "../data/bats_climatology.txt" + max_lines = 3000 + obs_out_dir = '../obs_seq_files', + debug = .true. + / + +&preprocess_nml + input_obs_def_mod_file = '../../../../observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '../../../../observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '../../../../observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '../../../../assimilation_code/modules/observations/default_quantities_mod.f90', '../../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' + / + +&obs_kind_nml + assimilate_these_obs_types = 'BATS_OXYGEN', + 'BATS_INORGANIC_CARBON', + 'BATS_ALKALINITY', + 'BATS_NITRATE', + 'BATS_PHOSPHATE', + 'BATS_SILICATE' + / + +&location_nml + / + +&utilities_nml + module_details = .false. + / + +&obs_sequence_nml + write_binary_obs_sequence = .false. + / + +&obs_sequence_tool_nml + filename_seq = 'obs_seq.out' + filename_seq_list = '' + filename_out = 'obs_seq.copy' + print_only = .false. + gregorian_cal = .true. + first_obs_days = -1 + first_obs_seconds = -1 + last_obs_days = -1 + last_obs_seconds = -1 + / + diff --git a/observations/obs_converters/BATS_clim/work/quickbuild.sh b/observations/obs_converters/BATS_clim/work/quickbuild.sh new file mode 100755 index 0000000000..e0a572ae0a --- /dev/null +++ b/observations/obs_converters/BATS_clim/work/quickbuild.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# DART software - Copyright UCAR. This open source software is provided +# by UCAR, "as is", without charge, subject to all terms of use at +# http://www.image.ucar.edu/DAReS/DART/DART_download + +main() { + +export DART=$(git rev-parse --show-toplevel) +source "$DART"/build_templates/buildconvfunctions.sh + +CONVERTER=BATS_clim +LOCATION=threed_sphere + + +programs=( +bats_to_clim_obs +obs_sequence_tool +advance_time +) + +# build arguments +arguments "$@" + +# clean the directory +\rm -f -- *.o *.mod Makefile .cppdefs + +# build and run preprocess before making any other DART executables +buildpreprocess + +# build +buildconv + + +# clean up +\rm -f -- *.o *.mod + +} + +main "$@" From 178bf705879de487ed85b9bfa0113cbca58dc00f Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Mon, 29 Jan 2024 21:00:00 -0700 Subject: [PATCH 09/35] Cleaned up code for MARBL_param_estimation and the corresponding data converter. --- models/MARBL_param_estimation/model_mod.f90 | 20 ++++++++----------- .../BATS_clim/bats_climatology.py | 17 ++++++++-------- .../BATS_clim/bats_to_clim_obs.f90 | 2 +- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 index a6ea060d38..d42f0c71be 100644 --- a/models/MARBL_param_estimation/model_mod.f90 +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -97,7 +97,6 @@ module model_mod character(len=256) :: template_file(2) integer :: time_step_days integer :: time_step_seconds -logical :: estimate_params character(len=vtablenamelength) & :: model_state_variables(modelvar_table_height * modelvar_table_width) character(len=vtablenamelength) & @@ -107,7 +106,6 @@ module model_mod time_step_days, & time_step_seconds, & model_state_variables, & - estimate_params, & model_parameters contains @@ -165,16 +163,14 @@ subroutine static_init_model() update_list = update_var_list(1:nfields)) ! setting up the DART parameter vector -if(estimate_params) then - call verify_state_variables(model_parameters, nfields, param_table, & - param_qty_list, param_clamp_vals, update_param_list) - - param_dom_id = add_domain(template_file(2), nfields, & - var_names = param_table(1:nfields, 1), & - kind_list = param_qty_list(1:nfields), & - clamp_vals = param_clamp_vals, & - update_list = update_param_list(1:nfields)) -end if +call verify_state_variables(model_parameters, nfields, param_table, & + param_qty_list, param_clamp_vals, update_param_list) + +param_dom_id = add_domain(template_file(2), nfields, & + var_names = param_table(1:nfields, 1), & + kind_list = param_qty_list(1:nfields), & + clamp_vals = param_clamp_vals, & + update_list = update_param_list(1:nfields)) call read_num_layers ! setting the value of nz diff --git a/observations/obs_converters/BATS_clim/bats_climatology.py b/observations/obs_converters/BATS_clim/bats_climatology.py index 255762d648..fbefbe63eb 100644 --- a/observations/obs_converters/BATS_clim/bats_climatology.py +++ b/observations/obs_converters/BATS_clim/bats_climatology.py @@ -23,13 +23,13 @@ [158, 164], # PO41 [166, 172]] # Si1 -# layer interface depths for data in prog_z.nc output file from MARBL +# layer interface depths for data in prog_z.nc output file from MARBL, run "ncdump -v "z_i" prog_z.nc" to generate. marbl_depths = [0, 5, 15, 25, 40, 62.5, 87.5, 112.5, 137.5, 175, 225, 275, 350, 450, 550, 650, 750, 850, 950, 1050, 1150, 1250, 1350, 1450, 1625, 1875, 2250, 2750, 3250, 3750, 4250, 4750, 5250, 5750, 6250] # set to 'True' in order to produce a histogram of BATS observation vs depth for each month -plot_sample_hist = True +plot_sample_hist = False # human-readable names of the variables being read from the file obs_names = ["O2", "CO2", "Alk", "NO31", "PO41", "Si1"] @@ -50,9 +50,6 @@ if(line_number < first_data_line): continue - - if(line_number % 1000 == 0): - print("processing line",line_number,"...") # extracting the depth and month where this observation was taken @@ -84,6 +81,8 @@ sample_counts[obs_type_index, month_index, depth_index] += 1 + print("month =",month_index,", type =",obs_type_index,", depth =",marbl_depths[depth_index],", value =",obs_val) + bats_data.close() # writing the climatology into a CSV file that will be readable by a DART data converter @@ -100,11 +99,11 @@ mean = clim_means[obs_type_index, month_index, depth_index] sq_mean = sq_means[obs_type_index, month_index, depth_index] - variability = (sq_mean - mean**2)/samples - obs_error = (.1*mean)**2 - uq = variability + obs_error + variability_err = (sq_mean - mean**2)/samples + obs_error = (.1*mean)**2 + uncertainty = variability_err + obs_error - clim_file.write(str(month_index+1)+","+str(obs_type_index+1)+","+str(depth)+","+str(mean)+","+str(uq)+"\n") + clim_file.write(str(month_index+1)+","+str(obs_type_index+1)+","+str(depth)+","+str(mean)+","+str(uncertainty)+"\n") clim_file.close() diff --git a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 index 104fb5f2bd..bb03883dfc 100644 --- a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 +++ b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 @@ -175,7 +175,7 @@ program bats_to_clim_obs if((OTYPE_ORDERING(otype_index) == BATS_ALKALINITY) .or. (OTYPE_ORDERING(otype_index) == BATS_INORGANIC_CARBON)) then ovalue = ovalue*1.026 - obs_err = obs_err*1.026**2 ! check with Helen to make sure that obs_err is a variance and not a standard deviation + obs_err = obs_err*1.026**2 end if if(debug) then From 64bee6f2fc58aa9948f5b5be1ef03142b41ccdcc Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Tue, 30 Jan 2024 08:58:20 -0700 Subject: [PATCH 10/35] Revisions to MARBL_param_estimation, which now runs data assimilation cycles with MARBL without errors. Further testing needed to assess the quality of assimilations. --- models/MARBL_param_estimation/model_mod.f90 | 32 +++++++------------ .../BATS_clim/bats_to_clim_obs.f90 | 18 ++++++----- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 index d42f0c71be..d398c57790 100644 --- a/models/MARBL_param_estimation/model_mod.f90 +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -156,11 +156,11 @@ subroutine static_init_model() call verify_state_variables(model_state_variables, nfields, variable_table, & state_qty_list, state_clamp_vals, update_var_list) - state_dom_id = add_domain(template_file(1), nfields, & - var_names = variable_table(1:nfields, 1), & - kind_list = state_qty_list(1:nfields), & - clamp_vals = state_clamp_vals, & - update_list = update_var_list(1:nfields)) +state_dom_id = add_domain(template_file(1), nfields, & + var_names = variable_table(1:nfields, 1), & + kind_list = state_qty_list(1:nfields), & + clamp_vals = state_clamp_vals, & + update_list = update_var_list(1:nfields)) ! setting up the DART parameter vector call verify_state_variables(model_parameters, nfields, param_table, & @@ -177,27 +177,17 @@ subroutine static_init_model() end subroutine static_init_model !------------------------------------------------------------------ -! Reads the simulation length from a netCDF file. +! Reads the simulation length from a netCDF file. Because the netCDF +! files in this model contain climatological data (not associated with +! a particular time), this function returns a dummy "0, 0" timestamp. function read_model_time(filename) character(len=*), intent(in) :: filename -type(time_type) :: read_model_time +type(time_type) :: read_model_time +character(len=*), parameter :: routine = 'read_model_time' -integer :: ncid -character(len=*), parameter :: routine = 'read_model_time' -real(r8) :: days -integer :: clim_day - -ncid = nc_open_file_readonly(filename, routine) - -call nc_get_variable(ncid, 'Time', days, routine) - -call nc_close_file(ncid, routine) - -clim_day = int(days) - -read_model_time = set_time(0,clim_day) +read_model_time = set_time(0,0) end function read_model_time diff --git a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 index bb03883dfc..aae9a25607 100644 --- a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 +++ b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 @@ -178,22 +178,24 @@ program bats_to_clim_obs obs_err = obs_err*1.026**2 end if + ! For ensemble smoothing, each observation is considered to be a measurement + ! of the same climatological "year", which is arbitrarily labeled as year 1601 + ! (the first year in DART's internal calendar). Observations are given identical + ! day/hour/minute timestamps to avoid time-ordering errors in the obs-seq file. + + time_obs = set_date(1601, 1, 1, hours=0, minutes=0) + call get_time(time_obs, osec, days=oday) + if(debug) then print *, "adding climatological mean for month ",month print *, " \__ type: ",OTYPE_ORDERING(otype_index) print *, " vert: ",vert print *, " value: ",ovalue print *, " uncertainty: ",obs_err + print *, " oday: ",oday + print *, " osec: ",osec end if - ! For ensemble smoothing, each observation is considered to be a measurement - ! of the same climatological "year", which is arbitrarily labeled as year 1601 - ! (the first year in DART's internal calendar). Observations are given identical - ! day/hour/minute timestamps to avoid time-ordering errors in the obs-seq file. - - time_obs = set_date(1601, month, 1, hours=0, minutes=0) - call get_time(time_obs, osec, days=oday) - new_obs_seq = (first_obs .or. (month /= month_old)) month_old = month From 2bfc151ab12148988e5b1efac2a121666409e74d Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Wed, 7 Feb 2024 21:34:45 -0700 Subject: [PATCH 11/35] MARBL_param_estimation now estimates only a single parameter, bats_climatology.py now records observation error in units of standard deviation, and the script also generates a surrogate netCDF file containing the BATS empirical climatology. --- models/MARBL_param_estimation/model_mod.f90 | 2 +- .../BATS_clim/bats_climatology.py | 42 +++++++++++++++---- .../BATS_clim/bats_to_clim_obs.f90 | 2 +- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 index d398c57790..2dfc3ced2b 100644 --- a/models/MARBL_param_estimation/model_mod.f90 +++ b/models/MARBL_param_estimation/model_mod.f90 @@ -90,7 +90,7 @@ module model_mod ! parameters to be used in specifying the DART internal state integer, parameter :: modelvar_table_height = 13 integer, parameter :: modelvar_table_width = 5 -integer, parameter :: modelparams_table_height = 2 +integer, parameter :: modelparams_table_height = 1 integer, parameter :: modelparams_table_width = 5 ! defining the variables that will be read from the namelist diff --git a/observations/obs_converters/BATS_clim/bats_climatology.py b/observations/obs_converters/BATS_clim/bats_climatology.py index fbefbe63eb..4978775e07 100644 --- a/observations/obs_converters/BATS_clim/bats_climatology.py +++ b/observations/obs_converters/BATS_clim/bats_climatology.py @@ -1,4 +1,6 @@ +import os import numpy as np +import netCDF4 as nc import matplotlib.pyplot as plt ################################################################# @@ -6,8 +8,9 @@ ################################################################# # input and output datafiles -input_file = 'data/bats_bottle.txt' -output_file = 'data/bats_climatology.txt' +input_file_path = 'data/bats_bottle.txt' +output_txt_path = 'data/bats_climatology.txt' +output_nc_path = 'data/bats_climatology.nc' first_data_line = 61 # file is read starting at this line (so that header information is ignored) month_columns = [18, 19] # first and last columns in the data file containing month values @@ -42,7 +45,7 @@ sq_means = np.zeros((num_obs_types, 12, len(marbl_depths))) sample_counts = np.zeros((num_obs_types, 12, len(marbl_depths)), dtype=int) -bats_data = open(input_file, "r") +bats_data = open(input_file_path, "r") line_number = 0 for line in bats_data.readlines(): @@ -85,14 +88,31 @@ bats_data.close() -# writing the climatology into a CSV file that will be readable by a DART data converter +# setting up a CSV file to write the climatology into; this will be read by the DART data converter. -clim_file = open(output_file, "w") +os.system("rm -f "+output_txt_path) +output_txt = open(output_txt_path, "w") + +# setting up a netCDF file to write the climatology into; this will be useful for creating MARBL-DART diagnostics. + +os.system("rm -f "+output_nc_path) +output_nc = nc.Dataset(output_nc_path, "w") + +output_nc.createDimension("Month") +output_nc.createDimension("Layer") +output_nc.createVariable("Depth", "double", ("Layer",)) +output_nc["Depth"][:] = marbl_depths + +for obs_type_index in range(num_obs_types): + output_nc.createVariable(obs_names[obs_type_index]+"_value", "double", ("Month", "Layer",)) + output_nc.createVariable(obs_names[obs_type_index]+"_error_sd", "double", ("Month", "Layer",)) + output_nc.createVariable(obs_names[obs_type_index]+"_samples", "int", ("Month", "Layer",)) for month_index in range(12): for obs_type_index in range(num_obs_types): for depth_index in range(len(marbl_depths)): samples = sample_counts[obs_type_index, month_index, depth_index] + output_nc[obs_names[obs_type_index]+"_samples"][month_index, depth_index] = samples if(samples > 0): depth = marbl_depths[depth_index] @@ -101,15 +121,19 @@ variability_err = (sq_mean - mean**2)/samples obs_error = (.1*mean)**2 - uncertainty = variability_err + obs_error + uncertainty = np.sqrt(variability_err + obs_error) - clim_file.write(str(month_index+1)+","+str(obs_type_index+1)+","+str(depth)+","+str(mean)+","+str(uncertainty)+"\n") + output_txt.write(str(month_index+1)+","+str(obs_type_index+1)+","+str(depth)+","+str(mean)+","+str(uncertainty)+"\n") -clim_file.close() + output_nc[obs_names[obs_type_index]+"_value"][month_index, depth_index] = mean + output_nc[obs_names[obs_type_index]+"_error_sd"][month_index, depth_index] = uncertainty + +output_txt.close() +output_nc.close() if(plot_sample_hist): - month_plot = 12*[None] month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] + month_plot = 12*[None] fig = plt.figure(figsize = (6, 70)) diff --git a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 index aae9a25607..c26672573a 100644 --- a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 +++ b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 @@ -163,7 +163,7 @@ program bats_to_clim_obs exit obsloop end if - ! reading the observtaion uncertainty + ! reading the observtaion uncertainty (standard deviation) read(input_line((comma_locs(4) + 1):len(input_line)), *, iostat=rcio) obs_err if(rcio /= 0) then From 6e826ea4867140e18864303dd869120dd235d2e3 Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Thu, 8 Feb 2024 20:26:39 -0700 Subject: [PATCH 12/35] Made observation error variance inflation a namelist parameter in the BATS_clim data converter. --- .../obs_converters/BATS_clim/bats_to_clim_obs.f90 | 13 +++++++++---- .../obs_converters/BATS_clim/work/input.nml | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 index c26672573a..7dcd511f14 100644 --- a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 +++ b/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 @@ -43,10 +43,11 @@ program bats_to_clim_obs ! namelist variables, changeable at runtime character(len=256) :: text_input_file, obs_out_dir -integer :: max_lines -logical :: debug +integer :: max_lines +real(r8) :: obs_err_var_inflation +logical :: debug -namelist /bats_to_clim_obs_nml/ text_input_file, max_lines, obs_out_dir, debug +namelist /bats_to_clim_obs_nml/ text_input_file, max_lines, obs_err_var_inflation, obs_out_dir, debug ! local variables character (len=294) :: input_line, obs_out_file @@ -171,11 +172,15 @@ program bats_to_clim_obs exit obsloop end if + ! inflating the observation error according to the number of cycles in MARBL-DART + + obs_err = obs_err*sqrt(obs_err_var_inflation) + ! unit corrections from BATS to MARBL if((OTYPE_ORDERING(otype_index) == BATS_ALKALINITY) .or. (OTYPE_ORDERING(otype_index) == BATS_INORGANIC_CARBON)) then ovalue = ovalue*1.026 - obs_err = obs_err*1.026**2 + obs_err = obs_err*1.026 end if ! For ensemble smoothing, each observation is considered to be a measurement diff --git a/observations/obs_converters/BATS_clim/work/input.nml b/observations/obs_converters/BATS_clim/work/input.nml index f178f80273..9e558d88cb 100644 --- a/observations/obs_converters/BATS_clim/work/input.nml +++ b/observations/obs_converters/BATS_clim/work/input.nml @@ -2,6 +2,7 @@ &bats_to_clim_obs_nml text_input_file = "../data/bats_climatology.txt" max_lines = 3000 + obs_err_var_inflation = 10 obs_out_dir = '../obs_seq_files', debug = .true. / From 9e2d45744e42be9d76517cfd1bf61c466b1dbf6f Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Mon, 12 Feb 2024 20:33:17 -0700 Subject: [PATCH 13/35] Added QTY codes for additional MARBL parameters. --- .../modules/observations/ocean_quantities_mod.f90 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/assimilation_code/modules/observations/ocean_quantities_mod.f90 b/assimilation_code/modules/observations/ocean_quantities_mod.f90 index 600feb00a5..5abc85201e 100644 --- a/assimilation_code/modules/observations/ocean_quantities_mod.f90 +++ b/assimilation_code/modules/observations/ocean_quantities_mod.f90 @@ -49,6 +49,8 @@ ! QTY_PARAM_AUTOTROPH1_KNO3 ! QTY_PARAM_AUTOTROPH1_KPO4 ! QTY_PARAM_AUTOTROPH1_KSIO3 +! QTY_PARAM_AUTOTROPH1_ALPHAPI +! QTY_PARAM_AUTOTROPH1_PCREF ! QTY_PARAM_AUTOTROPH2_KCO2 ! QTY_PARAM_AUTOTROPH2_KDOP ! QTY_PARAM_AUTOTROPH2_KFE @@ -56,6 +58,8 @@ ! QTY_PARAM_AUTOTROPH2_KNO3 ! QTY_PARAM_AUTOTROPH2_KPO4 ! QTY_PARAM_AUTOTROPH2_KSIO3 +! QTY_PARAM_AUTOTROPH2_ALPHAPI +! QTY_PARAM_AUTOTROPH2_PCREF ! QTY_PARAM_AUTOTROPH3_KCO2 ! QTY_PARAM_AUTOTROPH3_KDOP ! QTY_PARAM_AUTOTROPH3_KFE @@ -63,6 +67,8 @@ ! QTY_PARAM_AUTOTROPH3_KNO3 ! QTY_PARAM_AUTOTROPH3_KPO4 ! QTY_PARAM_AUTOTROPH3_KSIO3 +! QTY_PARAM_AUTOTROPH3_ALPHAPI +! QTY_PARAM_AUTOTROPH3_PCREF ! QTY_PARAM_AUTOTROPH4_KCO2 ! QTY_PARAM_AUTOTROPH4_KDOP ! QTY_PARAM_AUTOTROPH4_KFE @@ -70,6 +76,9 @@ ! QTY_PARAM_AUTOTROPH4_KNO3 ! QTY_PARAM_AUTOTROPH4_KPO4 ! QTY_PARAM_AUTOTROPH4_KSIO3 +! QTY_PARAM_AUTOTROPH4_ALPHAPI +! QTY_PARAM_AUTOTROPH4_PCREF +! QTY_PARAM_GRAZING11_ZUMAX0 ! ! ! fixme - these units are hardcoded in obs_diag and shouldn't be ! QTY_U_WIND_COMPONENT From b126a16af5e7ee5f4ecd8d0e94262e8e054056c5 Mon Sep 17 00:00:00 2001 From: Robin Armstrong Date: Thu, 11 Jul 2024 15:15:29 -0600 Subject: [PATCH 14/35] Changes to the joint state-parameter estimation model-mod and namelist, so that it works with the self-contained test package. --- models/MARBL_joint_estimation/model_mod.f90 | 3 +- models/MARBL_joint_estimation/work/input.nml | 33 ++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/models/MARBL_joint_estimation/model_mod.f90 b/models/MARBL_joint_estimation/model_mod.f90 index e73c58c5be..c9d0fdfc17 100644 --- a/models/MARBL_joint_estimation/model_mod.f90 +++ b/models/MARBL_joint_estimation/model_mod.f90 @@ -76,7 +76,6 @@ module model_mod character(len=256), parameter :: source = "model_mod.f90" -character(len=256), parameter :: ocean_geometry = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/baseline/ocean_geometry.nc" logical :: module_initialized = .false. integer :: state_dom_id ! used to access the state structure integer :: param_dom_id ! used to access MARBL internal parameters @@ -96,6 +95,7 @@ module model_mod ! defining the variables that will be read from the namelist character(len=256) :: template_file(2) +character(len=256) :: ocean_geometry integer :: time_step_days integer :: time_step_seconds logical :: estimate_params @@ -105,6 +105,7 @@ module model_mod :: model_parameters(modelparams_table_height * modelparams_table_width) namelist /model_nml/ template_file, & + ocean_geometry, & time_step_days, & time_step_seconds, & model_state_variables, & diff --git a/models/MARBL_joint_estimation/work/input.nml b/models/MARBL_joint_estimation/work/input.nml index bbdf1a7cb8..2fb9e3637a 100644 --- a/models/MARBL_joint_estimation/work/input.nml +++ b/models/MARBL_joint_estimation/work/input.nml @@ -30,21 +30,21 @@ &filter_nml single_file_in = .false., input_state_files = '', - input_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_params.txt', + input_state_file_list = 'states_input.txt', 'params_input.txt', stages_to_write = 'preassim', 'analysis', 'output', single_file_out = .false., output_state_files = '', - output_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/DART/ensemble_params.txt', + output_state_file_list = 'states_output.txt', 'params_output.txt', output_interval = 1, output_members = .true., - num_output_state_members = 80, + num_output_state_members = 3, output_mean = .true., output_sd = .true., write_all_stages_at_end = .true., - ens_size = 80, + ens_size = 3, num_groups = 1, perturb_from_single_instance = .false., perturbation_amplitude = 1e-2, @@ -53,9 +53,9 @@ async = 0, adv_ens_command = "./advance_model.csh", - obs_sequence_in_name ='/glade/u/home/rarmstrong/work/DART/observations/obs_converters/BATS/obs_seq_files/BATS_149468.out', - obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/output/149468/obs_seq.final', - num_output_obs_members = 80, + obs_sequence_in_name ='../../data/obs_seq_files/BATS_147612.out', + obs_sequence_out_name ='obs_seq.final', + num_output_obs_members = 3, init_time_days = -1, init_time_seconds = -1, first_obs_days = -1, @@ -90,7 +90,7 @@ post_inf_mean = 1.00, post_inf_sd = 0.6, - input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/marbl_params.nc', + input_state_files = '../ensemble/background/member_0001/RESTART/MOM.res.nc', '../ensemble/background/member_0001/marbl_params.nc', single_file = .false., verbose = .false. / @@ -139,7 +139,8 @@ / &model_nml - template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/ensemble/member_0001/marbl_params.nc', + template_file = '../ensemble/background/member_0001/RESTART/MOM.res.nc', '../ensemble/background/member_0001/marbl_params.nc', + ocean_geometry = '../ensemble/background/member_0001/ocean_geometry.nc', time_step_days = 1, time_step_seconds = 0, model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', @@ -168,12 +169,12 @@ / &preprocess_nml - input_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' - output_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_mod.f90' - input_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' - output_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/obs_kind_mod.f90' - obs_type_files = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/default_quantities_mod.f90', '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/ocean_quantities_mod.f90' + input_obs_def_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/default_quantities_mod.f90', '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/ocean_quantities_mod.f90' / &obs_sequence_tool_nml @@ -219,7 +220,7 @@ / &model_mod_check_nml - input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' + input_state_files = '../bg_ensemble/baseline/RESTART/MOM.res.nc' output_state_files = 'testing/model_mod_check_output/output.nc' test1thru = 0, run_tests = 1,2,3,4,5,6,7 From b54a467279075d9606274639a3773c262ce2843a Mon Sep 17 00:00:00 2001 From: Helen Kershaw Date: Mon, 15 Jul 2024 12:41:47 -0400 Subject: [PATCH 15/35] revert mpi utilities to main --- .../modules/utilities/mpi_utilities_mod.f90 | 24 +++++++++---------- .../utilities/mpif08_utilities_mod.f90 | 24 +++++++++---------- .../utilities/null_mpi_utilities_mod.f90 | 24 +++++++++---------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/assimilation_code/modules/utilities/mpi_utilities_mod.f90 b/assimilation_code/modules/utilities/mpi_utilities_mod.f90 index 0f90677fa9..90797018e8 100644 --- a/assimilation_code/modules/utilities/mpi_utilities_mod.f90 +++ b/assimilation_code/modules/utilities/mpi_utilities_mod.f90 @@ -102,18 +102,18 @@ module mpi_utilities_mod ! this directory. It is a sed script that comments in and out the interface ! block below. Please leave the BLOCK comment lines unchanged. - !!SYSTEM_BLOCK_EDIT START COMMENTED_IN - !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) - ! interface block for getting return code back from system() routine - interface - function system(string) - character(len=*) :: string - integer :: system - end function system - end interface - ! end block - !#endif - !!SYSTEM_BLOCK_EDIT END COMMENTED_IN +! !!SYSTEM_BLOCK_EDIT START COMMENTED_OUT +! !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) +! ! interface block for getting return code back from system() routine +! interface +! function system(string) +! character(len=*) :: string +! integer :: system +! end function system +! end interface +! ! end block +! !#endif +! !!SYSTEM_BLOCK_EDIT END COMMENTED_OUT ! allow global sum to be computed for integers, r4, and r8s diff --git a/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 b/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 index 4e423e1e6d..dee8c618d1 100644 --- a/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 +++ b/assimilation_code/modules/utilities/mpif08_utilities_mod.f90 @@ -102,18 +102,18 @@ module mpi_utilities_mod ! this directory. It is a sed script that comments in and out the interface ! block below. Please leave the BLOCK comment lines unchanged. - !!SYSTEM_BLOCK_EDIT START COMMENTED_IN - !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) - ! interface block for getting return code back from system() routine - interface - function system(string) - character(len=*) :: string - integer :: system - end function system - end interface - ! end block - !#endif - !!SYSTEM_BLOCK_EDIT END COMMENTED_IN +! !!SYSTEM_BLOCK_EDIT START COMMENTED_OUT +! !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) +! ! interface block for getting return code back from system() routine +! interface +! function system(string) +! character(len=*) :: string +! integer :: system +! end function system +! end interface +! ! end block +! !#endif +! !!SYSTEM_BLOCK_EDIT END COMMENTED_OUT ! allow global sum to be computed for integers, r4, and r8s diff --git a/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 b/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 index 30fa1d5ecd..cc729c23aa 100644 --- a/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 +++ b/assimilation_code/modules/utilities/null_mpi_utilities_mod.f90 @@ -74,18 +74,18 @@ module mpi_utilities_mod ! this directory. It is a sed script that comments in and out the interface ! block below. Please leave the BLOCK comment lines unchanged. - !!SYSTEM_BLOCK_EDIT START COMMENTED_IN - !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) - ! interface block for getting return code back from system() routine - interface - function system(string) - character(len=*) :: string - integer :: system - end function system - end interface - ! end block - !#endif - !!SYSTEM_BLOCK_EDIT END COMMENTED_IN +! !!SYSTEM_BLOCK_EDIT START COMMENTED_OUT +! !#if .not. defined (__GFORTRAN__) .and. .not. defined(__NAG__) +! ! interface block for getting return code back from system() routine +! interface +! function system(string) +! character(len=*) :: string +! integer :: system +! end function system +! end interface +! ! end block +! !#endif +! !!SYSTEM_BLOCK_EDIT END COMMENTED_OUT ! allow global sum to be computed for integers, r4, and r8s From 5917450769defdd6c3e53a56c276b1fbe375fae9 Mon Sep 17 00:00:00 2001 From: Helen Kershaw Date: Mon, 15 Jul 2024 12:59:43 -0400 Subject: [PATCH 16/35] remove netcdf files from MARBL directories --- .../MARBL_joint_estimation/work/output_mean.nc | Bin 27140 -> 0 bytes models/MARBL_joint_estimation/work/output_sd.nc | Bin 27128 -> 0 bytes .../work/model_mod_check_output.nc | Bin 4128 -> 0 bytes .../MARBL_param_estimation/work/output_mean.nc | Bin 27140 -> 0 bytes models/MARBL_param_estimation/work/output_sd.nc | Bin 27128 -> 0 bytes .../MARBL_state_estimation/work/output_mean.nc | Bin 27140 -> 0 bytes models/MARBL_state_estimation/work/output_sd.nc | Bin 27128 -> 0 bytes 7 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 models/MARBL_joint_estimation/work/output_mean.nc delete mode 100644 models/MARBL_joint_estimation/work/output_sd.nc delete mode 100644 models/MARBL_param_estimation/work/model_mod_check_output.nc delete mode 100644 models/MARBL_param_estimation/work/output_mean.nc delete mode 100644 models/MARBL_param_estimation/work/output_sd.nc delete mode 100644 models/MARBL_state_estimation/work/output_mean.nc delete mode 100644 models/MARBL_state_estimation/work/output_sd.nc diff --git a/models/MARBL_joint_estimation/work/output_mean.nc b/models/MARBL_joint_estimation/work/output_mean.nc deleted file mode 100644 index 62479604a15655cb2f94ee6cce37dd8c804e1bbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27140 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 Date: Mon, 15 Jul 2024 13:04:02 -0400 Subject: [PATCH 17/35] remove binary file null it is actually a netcdf file --- models/MARBL_param_estimation/work/null | Bin 4096 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 models/MARBL_param_estimation/work/null diff --git a/models/MARBL_param_estimation/work/null b/models/MARBL_param_estimation/work/null deleted file mode 100644 index 3b2020123489bdda27676f456ee2ab3168c59e6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmeHG!AcxK5FK?_cB5W`UJQY{EVvM4cC&&W#E66J!PO9R$t6uQ)1!?u-OEgmC?R)0 z!=s;&ugEcY%rE2|0;%eDT}6x{Ie6%TnyRj@>gxBVdMnzV41!<+^#v;V^&NgH3UpBB zQENu#!mff~7Ht!CE-nN&QY)5lbG1pe?N2B$7(f(3zfaEoKCDAG?Din+K)3>(E`+Pl zd+QFI&2=I&R_dyV=@>d=&c*P%oUVl~uWn<`r<{fn`7m>>7oyD%A6Y6h!K6xck=u)n zb6@Go3@ZadmC(U`NOaDn0+cRgy|ndr0X+rJj6Lfbj>WT($U?-1DPiIyWw&s(TFa1E%=sG0=RxM!sbN^g=+VU=9V?Nrlo}zl%o9GocbrPl{@4N-LW6dZnZ((Lu5C zgrCxq@H8lhsXsR^fBpXR{oBs7wP#;{eExFL-gu_g@#w#v0ndPEz%$?(@C Date: Mon, 15 Jul 2024 13:07:51 -0400 Subject: [PATCH 18/35] chore: remove .gitignore from various converters add executables to root/.gitignore --- .gitignore | 2 ++ observations/obs_converters/BATS/.gitignore | 3 --- observations/obs_converters/BATS_clim/.gitignore | 4 ---- observations/obs_converters/ocean_color/.gitignore | 1 - 4 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 observations/obs_converters/BATS/.gitignore delete mode 100644 observations/obs_converters/BATS_clim/.gitignore delete mode 100644 observations/obs_converters/ocean_color/.gitignore diff --git a/.gitignore b/.gitignore index bac4fbf326..52bfc9f8f8 100644 --- a/.gitignore +++ b/.gitignore @@ -158,6 +158,8 @@ ssec_satwnd gts_to_dart littler_tf_dart rad_3dvar_to_dart +bats_to_clim_obs +bats_to_obs # Test programs built by developer_tests rttov_test diff --git a/observations/obs_converters/BATS/.gitignore b/observations/obs_converters/BATS/.gitignore deleted file mode 100644 index 9cf7c75153..0000000000 --- a/observations/obs_converters/BATS/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -data/* -obs_seq_files/* -work/bats_to_obs diff --git a/observations/obs_converters/BATS_clim/.gitignore b/observations/obs_converters/BATS_clim/.gitignore deleted file mode 100644 index 8c479c6be6..0000000000 --- a/observations/obs_converters/BATS_clim/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -data/* -obs_seq_files/* -work/bats_to_clim_obs -*.pdf diff --git a/observations/obs_converters/ocean_color/.gitignore b/observations/obs_converters/ocean_color/.gitignore deleted file mode 100644 index 60baa9cb83..0000000000 --- a/observations/obs_converters/ocean_color/.gitignore +++ /dev/null @@ -1 +0,0 @@ -data/* From 864a61e85fc5eb81d05a247cf5a7e33b8dc9d5fa Mon Sep 17 00:00:00 2001 From: Helen Kershaw Date: Fri, 19 Jul 2024 07:17:11 -0600 Subject: [PATCH 19/35] fix: relative paths for preprocess input/output was pointing at Robin's directory --- models/MARBL_joint_estimation/work/input.nml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/models/MARBL_joint_estimation/work/input.nml b/models/MARBL_joint_estimation/work/input.nml index 2fb9e3637a..b1ddfb5ef1 100644 --- a/models/MARBL_joint_estimation/work/input.nml +++ b/models/MARBL_joint_estimation/work/input.nml @@ -169,12 +169,13 @@ / &preprocess_nml - input_obs_def_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' - output_obs_def_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/observations/forward_operators/obs_def_mod.f90' - input_obs_qty_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' - output_obs_qty_mod_file = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/obs_kind_mod.f90' - obs_type_files = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/default_quantities_mod.f90', '/glade/derecho/scratch/rarmstrong/marbl_dart/DART/assimilation_code/modules/observations/ocean_quantities_mod.f90' + input_obs_def_mod_file = '../../../observations/forward_operators/DEFAULT_obs_def_mod.F90' + output_obs_def_mod_file = '../../../observations/forward_operators/obs_def_mod.f90' + input_obs_qty_mod_file = '../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' + output_obs_qty_mod_file = '../../../assimilation_code/modules/observations/obs_kind_mod.f90' + obs_type_files = '../../../observations/forward_operators/obs_def_ocean_mod.f90' + quantity_files = '../../../assimilation_code/modules/observations/default_quantities_mod.f90', + '../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' / &obs_sequence_tool_nml From 81c7668fe7d047cfaa896e0b6aa0c4f228afab4e Mon Sep 17 00:00:00 2001 From: Helen Kershaw Date: Tue, 23 Jul 2024 14:03:30 -0400 Subject: [PATCH 20/35] remove _param_estimation and _state_estimation MARBL_joint_estimation is the model_mod we are using (see pull #701) --- models/MARBL_param_estimation/model_mod.f90 | 591 ---------------- models/MARBL_param_estimation/readme.rst | 5 - models/MARBL_param_estimation/work/input.nml | 241 ------- .../MARBL_param_estimation/work/metadata.txt | 300 -------- .../MARBL_param_estimation/work/quickbuild.sh | 59 -- models/MARBL_state_estimation/model_mod.f90 | 652 ------------------ models/MARBL_state_estimation/readme.rst | 5 - models/MARBL_state_estimation/work/input.nml | 238 ------- .../MARBL_state_estimation/work/quickbuild.sh | 59 -- 9 files changed, 2150 deletions(-) delete mode 100644 models/MARBL_param_estimation/model_mod.f90 delete mode 100644 models/MARBL_param_estimation/readme.rst delete mode 100644 models/MARBL_param_estimation/work/input.nml delete mode 100644 models/MARBL_param_estimation/work/metadata.txt delete mode 100755 models/MARBL_param_estimation/work/quickbuild.sh delete mode 100644 models/MARBL_state_estimation/model_mod.f90 delete mode 100644 models/MARBL_state_estimation/readme.rst delete mode 100644 models/MARBL_state_estimation/work/input.nml delete mode 100755 models/MARBL_state_estimation/work/quickbuild.sh diff --git a/models/MARBL_param_estimation/model_mod.f90 b/models/MARBL_param_estimation/model_mod.f90 deleted file mode 100644 index 2dfc3ced2b..0000000000 --- a/models/MARBL_param_estimation/model_mod.f90 +++ /dev/null @@ -1,591 +0,0 @@ -! DART software - Copyright UCAR. This open source software is provided -! by UCAR, "as is", without charge, subject to all terms of use at -! http://www.image.ucar.edu/DAReS/DART/DART_download -! - -module model_mod - -! This is a template showing the interfaces required for a model to be compliant -! with the DART data assimilation infrastructure. Do not change the arguments -! for the public routines. - -use types_mod, only : r8, i8, MISSING_R8, vtablenamelength - -use time_manager_mod, only : time_type, set_time - -use location_mod, only : location_type, get_close_type, & - loc_get_close_obs => get_close_obs, & - loc_get_close_state => get_close_state, & - set_location, set_location_missing, & - get_location, VERTISLEVEL - -use utilities_mod, only : register_module, error_handler, & - E_ERR, E_MSG, & - nmlfileunit, do_output, do_nml_file, do_nml_term, & - find_namelist_in_file, check_namelist_read, & - to_upper - -use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & - nc_add_global_creation_time, & - nc_begin_define_mode, nc_end_define_mode, & - NF90_MAX_NAME, nc_open_file_readonly, & - nc_get_variable, nc_get_variable_size, nc_close_file - -use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & - get_varid_from_kind, get_dart_vector_index - -use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & - QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & - QTY_COLUMN_DEPTH - -use distributed_state_mod, only: get_state - -use ensemble_manager_mod, only : ensemble_type - -! These routines are passed through from default_model_mod. -! To write model specific versions of these routines -! remove the routine from this use statement and add your code to -! this the file. -use default_model_mod, only : pert_model_copies, write_model_time, & - init_time => fail_init_time, & - init_conditions => fail_init_conditions, & - convert_vertical_obs, convert_vertical_state, adv_1step - -implicit none -private - -! routines required by DART code - will be called from filter and other -! DART executables. -public :: get_model_size, & - get_state_meta_data, & - model_interpolate, & - end_model, & - static_init_model, & - nc_write_model_atts, & - get_close_obs, & - get_close_state, & - pert_model_copies, & - convert_vertical_obs, & - convert_vertical_state, & - read_model_time, & - adv_1step, & - init_time, & - init_conditions, & - shortest_time_between_assimilations, & - write_model_time - - -character(len=256), parameter :: source = "model_mod.f90" -logical :: module_initialized = .false. -integer :: state_dom_id ! used to access the state structure -integer :: param_dom_id ! used to access MARBL internal parameters -integer :: nfields ! number of fields in the state or parameter vector -integer :: nz ! the number of vertical layers -integer :: model_size -type(time_type) :: assimilation_time_step -real(r8), parameter :: geolon = 360 - 64.0 -real(r8), parameter :: geolat = 31.0 -logical, parameter :: verbose_interpolation = .false. ! set this to .true. if you need to debug model_interpolate - -! parameters to be used in specifying the DART internal state -integer, parameter :: modelvar_table_height = 13 -integer, parameter :: modelvar_table_width = 5 -integer, parameter :: modelparams_table_height = 1 -integer, parameter :: modelparams_table_width = 5 - -! defining the variables that will be read from the namelist -character(len=256) :: template_file(2) -integer :: time_step_days -integer :: time_step_seconds -character(len=vtablenamelength) & - :: model_state_variables(modelvar_table_height * modelvar_table_width) -character(len=vtablenamelength) & - :: model_parameters(modelparams_table_height * modelparams_table_width) - -namelist /model_nml/ template_file, & - time_step_days, & - time_step_seconds, & - model_state_variables, & - model_parameters -contains - -!------------------------------------------------------------------ -! -! Called to do one time initialization of the model. As examples, -! might define information about the model size or model timestep. -! In models that require pre-computed static data, for instance -! spherical harmonic weights, these would also be computed here. - -subroutine static_init_model() - -integer :: iunit, io -character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width), & - param_table(modelparams_table_height, modelparams_table_width) -integer :: state_qty_list(modelvar_table_height), & - param_qty_list(modelparams_table_height) -real(r8):: state_clamp_vals(modelvar_table_height, 2), & - param_clamp_vals(modelparams_table_height, 2) -logical :: update_var_list(modelvar_table_height), & - update_param_list(modelparams_table_height) - -module_initialized = .true. - -! Print module information to log file and stdout. -call register_module(source) - -! Read values from the namelist - -call find_namelist_in_file("input.nml", "model_nml", iunit) -read(iunit, nml = model_nml, iostat = io) - -call check_namelist_read(iunit, io, "model_nml") - -! Record the namelist values used for the run -if (do_nml_file()) write(nmlfileunit, nml=model_nml) -if (do_nml_term()) write( * , nml=model_nml) - -! This time is both the minimum time you can ask the model to advance -! (for models that can be advanced by filter) and it sets the assimilation -! window. All observations within +/- 1/2 this interval from the current -! model time will be assimilated. If this is not settable at runtime -! feel free to hardcode it and remove from the namelist. -assimilation_time_step = set_time(time_step_seconds, & - time_step_days) - -! setting up the DART state vector -call verify_state_variables(model_state_variables, nfields, variable_table, & - state_qty_list, state_clamp_vals, update_var_list) - -state_dom_id = add_domain(template_file(1), nfields, & - var_names = variable_table(1:nfields, 1), & - kind_list = state_qty_list(1:nfields), & - clamp_vals = state_clamp_vals, & - update_list = update_var_list(1:nfields)) - -! setting up the DART parameter vector -call verify_state_variables(model_parameters, nfields, param_table, & - param_qty_list, param_clamp_vals, update_param_list) - -param_dom_id = add_domain(template_file(2), nfields, & - var_names = param_table(1:nfields, 1), & - kind_list = param_qty_list(1:nfields), & - clamp_vals = param_clamp_vals, & - update_list = update_param_list(1:nfields)) - -call read_num_layers ! setting the value of nz - -end subroutine static_init_model - -!------------------------------------------------------------------ -! Reads the simulation length from a netCDF file. Because the netCDF -! files in this model contain climatological data (not associated with -! a particular time), this function returns a dummy "0, 0" timestamp. - -function read_model_time(filename) - -character(len=*), intent(in) :: filename -type(time_type) :: read_model_time -character(len=*), parameter :: routine = 'read_model_time' - -read_model_time = set_time(0,0) - -end function read_model_time - -!------------------------------------------------------------------ -! Returns the number of items in the state vector as an integer. - -function get_model_size() - -integer(i8) :: get_model_size - -if ( .not. module_initialized ) call static_init_model - -get_model_size = get_domain_size(state_dom_id) + get_domain_size(param_dom_id) - -end function get_model_size - -!------------------------------------------------------------------ -! Given a state handle, a location, and a state quantity, -! interpolates the state variable fields to that location and returns -! the values in expected_obs. The istatus variables should be returned as -! 0 unless there is some problem in computing the interpolation in -! which case a positive istatus should be returned. -! -! For applications in which only perfect model experiments -! with identity observations (i.e. only the value of a particular -! state variable is observed), this can be a NULL INTERFACE. - -subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus) - -type(ensemble_type), intent(in) :: state_handle -integer, intent(in) :: ens_size -type(location_type), intent(in) :: location -integer, intent(in) :: qty -real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values -integer, intent(out) :: istatus(ens_size) - -integer :: qty_id, depth_id, qty_index, depth_index, ens_index, layer_index, layer_above, layer_below -real(8) :: requested_depth, theta -real(8) :: loc_temp(3), depths(nz), state_qty_tmp(ens_size), vals_above(ens_size), vals_below(ens_size) - -if ( .not. module_initialized ) call static_init_model - -! extracting the the depths at which climatological averages are available - -if (verbose_interpolation) then - print *, "===================================================================" - print *, "model_interpolate" - print *, "===================================================================" - print *, "" - print *, "querying layer depths from climatology file..." - print *, "" -end if - -depth_id = get_varid_from_kind(state_dom_id, QTY_COLUMN_DEPTH) - -do layer_index = 1, nz - depth_index = get_dart_vector_index(layer_index, 1, 1, state_dom_id, depth_id) - state_qty_tmp = get_state(depth_index, state_handle) - - ! gridpoint depths are identical across ensemble members, so we only need to query the first member. - depths(layer_index) = state_qty_tmp(1) - - if (verbose_interpolation) then - print *, " layer: ",layer_index,", depth: ",depths(layer_index) - end if -end do - -! extracting the requested depth value from `location` - -loc_temp = get_location(location) -requested_depth = loc_temp(3) - -! figuring out the nearest layers above and below the requested depth - -layer_above = 1 -layer_below = 1 - -do while((depths(layer_below) <= requested_depth) .and. (layer_below < nz)) - ! This executes as long as the requested depth is not shallower than the shallowest - ! layer in the climatology. - layer_below = layer_below + 1 - layer_above = layer_below - 1 -end do - -if (depths(layer_below) <= requested_depth) then - ! this executes if the requested depth was deeper than the deepest layer in the climatology. - layer_above = layer_below -end if - -if (verbose_interpolation) then - print *, "" - print *, "interpolating to depth: ",requested_depth - print *, "nearest layer index above: ",layer_above - print *, "nearest layer index below: ",layer_below - print *, "interpolating..." - print *, "" -end if - -! determining the ensemble values above and below the requested depth - -qty_id = get_varid_from_kind(state_dom_id, qty) - -qty_index = get_dart_vector_index(layer_above, 1, 1, state_dom_id, qty_id) -vals_above = get_state(qty_index, state_handle) - -qty_index = get_dart_vector_index(layer_below, 1, 1, state_dom_id, qty_id) -vals_below = get_state(qty_index, state_handle) - -! linear interpolation - -do ens_index = 1, ens_size - istatus(ens_index) = 0 - - if (layer_above < layer_below) then - theta = (depths(layer_below) - requested_depth)/(depths(layer_below) - depths(layer_above)) - expected_obs(ens_index) = theta*vals_above(ens_index) + (1 - theta)*vals_below(ens_index) - else - ! This block of code gets executed when the requested depth is shallower than the shallowest layer - ! in the climatology, or deeper than the deepest layer in the climatology. In either case, the "interpolated" - ! value is just the value of the closest layer, which is either the top layer or the bottom one. - - expected_obs(ens_index) = vals_below(ens_index) - end if - - if (verbose_interpolation) then - print *, " member: ",ens_index,", value above: ",vals_above(ens_index),", & - value below: ",vals_below(ens_index),", interpolation: ",expected_obs(ens_index) - end if -end do - -end subroutine model_interpolate - -!------------------------------------------------------------------ -! Returns the smallest increment in time that the model is capable -! of advancing the state in a given implementation, or the shortest -! time you want the model to advance between assimilations. - -function shortest_time_between_assimilations() - -type(time_type) :: shortest_time_between_assimilations - -if ( .not. module_initialized ) call static_init_model - -shortest_time_between_assimilations = assimilation_time_step - -end function shortest_time_between_assimilations - - - -!------------------------------------------------------------------ -! Given an integer index into the state vector, returns the -! associated location and optionally the physical quantity. - -subroutine get_state_meta_data(index_in, location, qty) - -integer(i8), intent(in) :: index_in -type(location_type), intent(out) :: location -integer, intent(out), optional :: qty - -real(r8) :: lat, lon -integer :: lon_index, lat_index, level, local_qty - -if ( .not. module_initialized ) call static_init_model - -call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) - -location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) - -if (present(qty)) then - qty = local_qty -endif - - -end subroutine get_state_meta_data - - -!------------------------------------------------------------------ -! Any model specific distance calcualtion can be done here -subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & - num_close, close_ind, dist, ens_handle) - -type(get_close_type), intent(in) :: gc ! handle to a get_close structure -integer, intent(in) :: base_type ! observation TYPE -type(location_type), intent(inout) :: base_loc ! location of interest -type(location_type), intent(inout) :: locs(:) ! obs locations -integer, intent(in) :: loc_qtys(:) ! QTYS for obs -integer, intent(in) :: loc_types(:) ! TYPES for obs -integer, intent(out) :: num_close ! how many are close -integer, intent(out) :: close_ind(:) ! incidies into the locs array -real(r8), optional, intent(out) :: dist(:) ! distances in radians -type(ensemble_type), optional, intent(in) :: ens_handle - -character(len=*), parameter :: routine = 'get_close_obs' - -call loc_get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & - num_close, close_ind, dist, ens_handle) - -end subroutine get_close_obs - - -!------------------------------------------------------------------ -! Any model specific distance calcualtion can be done here -subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & - num_close, close_ind, dist, ens_handle) - -type(get_close_type), intent(in) :: gc ! handle to a get_close structure -type(location_type), intent(inout) :: base_loc ! location of interest -integer, intent(in) :: base_type ! observation TYPE -type(location_type), intent(inout) :: locs(:) ! state locations -integer, intent(in) :: loc_qtys(:) ! QTYs for state -integer(i8), intent(in) :: loc_indx(:) ! indices into DART state vector -integer, intent(out) :: num_close ! how many are close -integer, intent(out) :: close_ind(:) ! indices into the locs array -real(r8), optional, intent(out) :: dist(:) ! distances in radians -type(ensemble_type), optional, intent(in) :: ens_handle - -character(len=*), parameter :: routine = 'get_close_state' - - -call loc_get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & - num_close, close_ind, dist, ens_handle) - - -end subroutine get_close_state - - -!------------------------------------------------------------------ -! Does any shutdown and clean-up needed for model. Can be a NULL -! INTERFACE if the model has no need to clean up storage, etc. - -subroutine end_model() - - -end subroutine end_model - - -!------------------------------------------------------------------ -! write any additional attributes to the output and diagnostic files - -subroutine nc_write_model_atts(ncid, domain_id) - -integer, intent(in) :: ncid ! netCDF file identifier -integer, intent(in) :: domain_id - -if ( .not. module_initialized ) call static_init_model - -! put file into define mode. - -call nc_begin_define_mode(ncid) - -call nc_add_global_creation_time(ncid) - -call nc_add_global_attribute(ncid, "model_source", source ) -call nc_add_global_attribute(ncid, "model", "template") - -call nc_end_define_mode(ncid) - -! Flush the buffer and leave netCDF file open -call nc_synchronize_file(ncid) - -end subroutine nc_write_model_atts - -!------------------------------------------------------------------ -! Verify that the namelist was filled in correctly, and check -! that there are valid entries for the dart_kind. -! Returns a table with columns: -! -! netcdf_variable_name ; dart_qty_string ; lowerbound ; upperbound ; update_string - -subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp_vals, update_var) - -character(len=*), intent(inout) :: state_variables(:) -integer, intent(out) :: ngood -character(len=*), intent(out) :: table(:,:) -integer, intent(out) :: qty_list(:) ! kind number -real(r8), intent(out) :: clamp_vals(:,:) -logical, intent(out) :: update_var(:) ! logical update - -integer :: nrows, i -character(len=NF90_MAX_NAME) :: varname, dartstr, lowerbound, upperbound, update -character(len=256) :: string1, string2 - -if ( .not. module_initialized ) call static_init_model - -nrows = size(table,1) - -ngood = 0 - -MyLoop : do i = 1, nrows - - varname = trim(state_variables(5*i -4)) - dartstr = trim(state_variables(5*i -3)) - lowerbound = trim(state_variables(5*i -2)) - upperbound = trim(state_variables(5*i -1)) - update = trim(state_variables(5*i )) - - call to_upper(update) - - table(i,1) = trim(varname) - table(i,2) = trim(dartstr) - table(i,3) = trim(lowerbound) - table(i,4) = trim(upperbound) - table(i,5) = trim(update) - - if ( table(i,1) == ' ' .and. table(i,2) == ' ' .and. table(i,3) == ' ' .and. table(i,4) == ' ' .and. table(i,5) == ' ') exit MyLoop ! Found end of list. - - if ( table(i,1) == ' ' .or. table(i,2) == ' ' .or. table(i,3) == ' ' .or. table(i,4) == ' ' .or. table(i,5) == ' ') then - string1 = 'model_nml:model_state_variables not fully specified' - call error_handler(E_ERR,'verify_state_variables',string1) - endif - - ! Make sure DART qty is valid - - qty_list(i) = get_index_for_quantity(dartstr) - if( qty_list(i) < 0 ) then - write(string1,'(''there is no obs_kind <'',a,''> in obs_kind_mod.f90'')') trim(dartstr) - call error_handler(E_ERR,'verify_state_variables',string1) - endif - - ! Make sure the update variable has a valid name - - select case (update) - case ('UPDATE') - update_var(i) = .true. - case ('NO_COPY_BACK') - update_var(i) = .false. - case default - write(string1,'(A)') 'only UPDATE or NO_COPY_BACK supported in model_state_variable namelist' - write(string2,'(6A)') 'you provided : ', trim(varname), ', ', trim(dartstr), ', ', trim(update) - call error_handler(E_ERR,'verify_state_variables',string1, text2=string2) - end select - - ! reading the clamp values - - if (table(i, 3) /= 'NA') then - read(table(i,3), '(d16.8)') clamp_vals(i,1) - else - clamp_vals(i,1) = MISSING_R8 - endif - - if (table(i,4) /= 'NA') then - read(table(i,4), '(d16.8)') clamp_vals(i,2) - else - clamp_vals(i,2) = MISSING_R8 - endif - - ngood = ngood + 1 -enddo MyLoop - - -end subroutine verify_state_variables - -!------------------------------------------------------------ -function on_v_grid(qty) - -integer, intent(in) :: qty -logical :: on_v_grid - -if (qty == QTY_V_CURRENT_COMPONENT) then - on_v_grid = .true. -else - on_v_grid = .false. -endif - -end function on_v_grid - -!---------------------------------------------------------- -function on_u_grid(qty) - -integer, intent(in) :: qty -logical :: on_u_grid - -if (qty == QTY_U_CURRENT_COMPONENT) then - on_u_grid = .true. -else - on_u_grid = .false. -endif - -end function on_u_grid - -!------------------------------------------------------------ -! Read number of vertical layers from mom6 template file -subroutine read_num_layers() - -integer :: ncid - -character(len=*), parameter :: routine = 'read_num_layers' - -ncid = nc_open_file_readonly(template_file(1)) - -call nc_get_variable_size(ncid, 'Layer', nz) - -call nc_close_file(ncid) - -end subroutine read_num_layers - -!=================================================================== -! End of model_mod -!=================================================================== -end module model_mod - diff --git a/models/MARBL_param_estimation/readme.rst b/models/MARBL_param_estimation/readme.rst deleted file mode 100644 index a42fe105d3..0000000000 --- a/models/MARBL_param_estimation/readme.rst +++ /dev/null @@ -1,5 +0,0 @@ -MARBL_param_estimation -======================= - -.. attention:: - Add your model documentation here. diff --git a/models/MARBL_param_estimation/work/input.nml b/models/MARBL_param_estimation/work/input.nml deleted file mode 100644 index 8d3b76685b..0000000000 --- a/models/MARBL_param_estimation/work/input.nml +++ /dev/null @@ -1,241 +0,0 @@ -&perfect_model_obs_nml - read_input_state_from_file = .true., - single_file_in = .false., - input_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/RESTART/DART_perfect_model_obs/MOM.res.nc", - - write_output_state_to_file = .true., - single_file_out = .false., - output_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/RESTART/DART_perfect_model_obs/MOM.res.output.nc", - output_interval = 1, - - async = 0, - adv_ens_command = "./advance_model.csh", - - obs_seq_in_file_name = "obs_seq.in", - obs_seq_out_file_name = "obs_seq.out", - init_time_days = 0, - init_time_seconds = 0, - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, - - trace_execution = .false., - output_timestamps = .false., - print_every_nth_obs = -1, - output_forward_op_errors = .false., - silence = .false., - / - -&filter_nml - single_file_in = .false., - input_state_files = '', - input_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_params.txt', - - stages_to_write = 'preassim', 'analysis', 'output', - - single_file_out = .false., - output_state_files = '', - output_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_states.txt', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/DART/ensemble_params.txt', - output_interval = 1, - output_members = .true., - num_output_state_members = 80, - output_mean = .true., - output_sd = .true., - write_all_stages_at_end = .true., - - ens_size = 80, - num_groups = 1, - perturb_from_single_instance = .false., - perturbation_amplitude = 1e-2, - distributed_state = .true., - - async = 0, - adv_ens_command = "./advance_model.csh", - - obs_sequence_in_name ='/glade/work/rarmstrong/BATS_obsseq/BATS_147638.out', - obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/output/147638/obs_seq.final', - num_output_obs_members = 80, - init_time_days = -1, - init_time_seconds = -1, - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, - - inf_flavor = 5, 0, - inf_initial_from_restart = .true., .false., - inf_sd_initial_from_restart = .true., .false., - inf_deterministic = .true., .true., - inf_initial = 1.0, 1.0, - inf_lower_bound = 0.0, 1.0, - inf_upper_bound = 100.0, 1000000.0, - inf_damping = 0.9, 1.0, - inf_sd_initial = 0.6, 0.0, - inf_sd_lower_bound = 0.6, 0.0, - inf_sd_max_change = 1.05, 1.05, - - trace_execution = .true., - output_timestamps = .false., - output_forward_op_errors = .false., - silence = .false., - / - -&fill_inflation_restart_nml - write_prior_inf = .true., - prior_inf_mean = 1.0, - prior_inf_sd = 0.6, - - write_post_inf = .false., - post_inf_mean = 1.00, - post_inf_sd = 0.6, - - input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/RESTART/MOM.res.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/INPUT/marbl_params.nc', - single_file = .false., - verbose = .false. - / - - -&ensemble_manager_nml - / - -&assim_tools_nml - filter_kind = 1, - cutoff = 1000000.0 - sort_obs_inc = .false., - spread_restoration = .false., - sampling_error_correction = .false., - adaptive_localization_threshold = -1, - distribute_mean = .false. - output_localization_diagnostics = .false., - localization_diagnostics_file = 'localization_diagnostics', - print_every_nth_obs = 0 - / - -&cov_cutoff_nml - select_localization = 1 - / - -®_factor_nml - select_regression = 1, - input_reg_file = "time_mean_reg", - save_reg_diagnostics = .false., - reg_diagnostics_file = "reg_diagnostics" - / - -&obs_sequence_nml - write_binary_obs_sequence = .false. - / - -&obs_kind_nml - assimilate_these_obs_types = 'BATS_OXYGEN', - 'BATS_ALKALINITY', - 'BATS_INORGANIC_CARBON', - 'BATS_SILICATE', - 'BATS_PHOSPHATE', - 'BATS_NITRATE', - evaluate_these_obs_types = 'BATS_NITROGEN', - 'BATS_ORGANIC_CARBON' - / - -&model_nml - template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/clim_000.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/params_000.nc' - time_step_days = 1, - time_step_seconds = 0, - model_state_variables = 'clim_NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', - 'clim_SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', - 'clim_PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', - 'clim_Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', - 'clim_DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', - 'clim_O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', - 'clim_DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', - 'clim_DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', - 'clim_DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', - 'clim_ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', - 'clim_microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'clim_mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'Layer ', 'QTY_COLUMN_DEPTH ', 'NA ', 'NA', 'NO_COPY_BACK' - estimate_params = .true. - model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE', - 'autotroph_settings(1)%kNH4 ', 'QTY_PARAM_AUTOTROPH1_KNH4 ', '0.0', 'NA', 'UPDATE' - / - -&utilities_nml - TERMLEVEL = 1, - module_details = .false., - logfilename = 'dart_log.out', - nmlfilename = 'dart_log.nml', - write_nml = 'none' - / - -&preprocess_nml - input_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' - output_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_mod.f90' - input_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' - output_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/obs_kind_mod.f90' - obs_type_files = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/default_quantities_mod.f90', '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/ocean_quantities_mod.f90' - / - -&obs_sequence_tool_nml - filename_seq = 'obs_seq.one', 'obs_seq.two', - filename_out = 'obs_seq.processed', - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, - print_only = .false., - gregorian_cal = .false. - / - -&obs_diag_nml - obs_sequence_name = '' - obs_sequence_list = 'obs_seq_list.txt' - first_bin_center = 2005, 2, 24, 0, 0, 0 - last_bin_center = 2010, 2, 28, 0, 0, 0 - bin_separation = 0, 0, 1, 0, 0, 0 - bin_width = 0, 0, 1, 0, 0, 0 - time_to_skip = 0, 0, 0, 0, 0, 0 - max_num_bins = 1000 - plevel = -888888.0 - hlevel = -1, -5, -10, -50, -100, -250, -500, -1000, -2000, -3000, -4000, -5000, -6000 - mlevel = -888888 - plevel_edges = -888888.0 - hlevel_edges = -888888.0 - mlevel_edges = -888888 - Nregions = 1 - lonlim1 = 0 - lonlim2 = 360 - latlim1 = -90 - latlim2 = 90 - reg_names = 'null' - trusted_obs = 'null' - create_rank_histogram = .true. - outliers_in_histogram = .false. - use_zero_error_obs = .false. - verbose = .false. - / - -&state_vector_io_nml - / - -&model_mod_check_nml - input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/clim_000.nc', '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_param_estimation/ensemble/member_0001/climatology/params_000.nc' - output_state_files = 'model_mod_check_output.nc' - test1thru = 0, - run_tests = 1,2,3,4,5,6,7 - x_ind = 261 - loc_of_interest = 1.11, 0.54, 45.0 - quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_NITROGEN' - interp_test_dx = 0.02 - interp_test_xrange = 0.0, 1.0 - verbose = .true. - / - -&quality_control_nml - input_qc_threshold = 3.0, - outlier_threshold = 3.0, -/ - -&location_nml - / diff --git a/models/MARBL_param_estimation/work/metadata.txt b/models/MARBL_param_estimation/work/metadata.txt deleted file mode 100644 index eb412ad0f4..0000000000 --- a/models/MARBL_param_estimation/work/metadata.txt +++ /dev/null @@ -1,300 +0,0 @@ - 1 i,j,k 1 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 2 i,j,k 2 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 3 i,j,k 3 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 4 i,j,k 4 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 5 i,j,k 5 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 6 i,j,k 6 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 7 i,j,k 7 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 8 i,j,k 8 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 9 i,j,k 9 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 10 i,j,k 10 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 11 i,j,k 11 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 12 i,j,k 12 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 13 i,j,k 13 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 14 i,j,k 14 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 15 i,j,k 15 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 16 i,j,k 16 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 17 i,j,k 17 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 18 i,j,k 18 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 19 i,j,k 19 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 20 i,j,k 20 1 1 domain 1 183 QTY_NITRATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 21 i,j,k 1 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 22 i,j,k 2 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 23 i,j,k 3 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 24 i,j,k 4 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 25 i,j,k 5 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 26 i,j,k 6 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 27 i,j,k 7 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 28 i,j,k 8 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 29 i,j,k 9 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 30 i,j,k 10 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 31 i,j,k 11 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 32 i,j,k 12 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 33 i,j,k 13 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 34 i,j,k 14 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 35 i,j,k 15 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 36 i,j,k 16 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 37 i,j,k 17 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 38 i,j,k 18 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 39 i,j,k 19 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 40 i,j,k 20 1 1 domain 1 69 QTY_DISSOLVED_INORGANIC_SIO3 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 41 i,j,k 1 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 42 i,j,k 2 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 43 i,j,k 3 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 44 i,j,k 4 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 45 i,j,k 5 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 46 i,j,k 6 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 47 i,j,k 7 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 48 i,j,k 8 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 49 i,j,k 9 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 50 i,j,k 10 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 51 i,j,k 11 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 52 i,j,k 12 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 53 i,j,k 13 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 54 i,j,k 14 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 55 i,j,k 15 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 56 i,j,k 16 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 57 i,j,k 17 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 58 i,j,k 18 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 59 i,j,k 19 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 60 i,j,k 20 1 1 domain 1 197 QTY_PHOSPHATE_CONCENTRATION Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 61 i,j,k 1 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 62 i,j,k 2 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 63 i,j,k 3 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 64 i,j,k 4 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 65 i,j,k 5 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 66 i,j,k 6 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 67 i,j,k 7 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 68 i,j,k 8 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 69 i,j,k 9 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 70 i,j,k 10 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 71 i,j,k 11 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 72 i,j,k 12 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 73 i,j,k 13 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 74 i,j,k 14 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 75 i,j,k 15 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 76 i,j,k 16 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 77 i,j,k 17 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 78 i,j,k 18 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 79 i,j,k 19 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 80 i,j,k 20 1 1 domain 1 68 QTY_DISSOLVED_INORGANIC_IRON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 81 i,j,k 1 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 82 i,j,k 2 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 83 i,j,k 3 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 84 i,j,k 4 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 85 i,j,k 5 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 86 i,j,k 6 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 87 i,j,k 7 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 88 i,j,k 8 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 89 i,j,k 9 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 90 i,j,k 10 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 91 i,j,k 11 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 92 i,j,k 12 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 93 i,j,k 13 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 94 i,j,k 14 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 95 i,j,k 15 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 96 i,j,k 16 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 97 i,j,k 17 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 98 i,j,k 18 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 99 i,j,k 19 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 100 i,j,k 20 1 1 domain 1 67 QTY_DISSOLVED_INORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 101 i,j,k 1 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 102 i,j,k 2 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 103 i,j,k 3 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 104 i,j,k 4 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 105 i,j,k 5 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 106 i,j,k 6 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 107 i,j,k 7 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 108 i,j,k 8 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 109 i,j,k 9 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 110 i,j,k 10 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 111 i,j,k 11 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 112 i,j,k 12 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 113 i,j,k 13 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 114 i,j,k 14 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 115 i,j,k 15 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 116 i,j,k 16 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 117 i,j,k 17 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 118 i,j,k 18 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 119 i,j,k 19 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 120 i,j,k 20 1 1 domain 1 73 QTY_DISSOLVED_OXYGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 121 i,j,k 1 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 122 i,j,k 2 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 123 i,j,k 3 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 124 i,j,k 4 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 125 i,j,k 5 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 126 i,j,k 6 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 127 i,j,k 7 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 128 i,j,k 8 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 129 i,j,k 9 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 130 i,j,k 10 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 131 i,j,k 11 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 132 i,j,k 12 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 133 i,j,k 13 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 134 i,j,k 14 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 135 i,j,k 15 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 136 i,j,k 16 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 137 i,j,k 17 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 138 i,j,k 18 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 139 i,j,k 19 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 140 i,j,k 20 1 1 domain 1 70 QTY_DISSOLVED_ORGANIC_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 141 i,j,k 1 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 142 i,j,k 2 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 143 i,j,k 3 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 144 i,j,k 4 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 145 i,j,k 5 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 146 i,j,k 6 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 147 i,j,k 7 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 148 i,j,k 8 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 149 i,j,k 9 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 150 i,j,k 10 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 151 i,j,k 11 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 152 i,j,k 12 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 153 i,j,k 13 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 154 i,j,k 14 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 155 i,j,k 15 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 156 i,j,k 16 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 157 i,j,k 17 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 158 i,j,k 18 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 159 i,j,k 19 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 160 i,j,k 20 1 1 domain 1 71 QTY_DISSOLVED_ORGANIC_NITROGEN Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 161 i,j,k 1 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 162 i,j,k 2 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 163 i,j,k 3 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 164 i,j,k 4 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 165 i,j,k 5 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 166 i,j,k 6 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 167 i,j,k 7 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 168 i,j,k 8 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 169 i,j,k 9 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 170 i,j,k 10 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 171 i,j,k 11 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 172 i,j,k 12 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 173 i,j,k 13 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 174 i,j,k 14 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 175 i,j,k 15 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 176 i,j,k 16 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 177 i,j,k 17 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 178 i,j,k 18 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 179 i,j,k 19 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 180 i,j,k 20 1 1 domain 1 72 QTY_DISSOLVED_ORGANIC_P Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 181 i,j,k 1 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 182 i,j,k 2 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 183 i,j,k 3 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 184 i,j,k 4 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 185 i,j,k 5 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 186 i,j,k 6 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 187 i,j,k 7 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 188 i,j,k 8 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 189 i,j,k 9 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 190 i,j,k 10 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 191 i,j,k 11 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 192 i,j,k 12 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 193 i,j,k 13 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 194 i,j,k 14 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 195 i,j,k 15 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 196 i,j,k 16 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 197 i,j,k 17 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 198 i,j,k 18 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 199 i,j,k 19 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 200 i,j,k 20 1 1 domain 1 12 QTY_ALKALINITY Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 201 i,j,k 1 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 202 i,j,k 2 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 203 i,j,k 3 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 204 i,j,k 4 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 205 i,j,k 5 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 206 i,j,k 6 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 207 i,j,k 7 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 208 i,j,k 8 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 209 i,j,k 9 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 210 i,j,k 10 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 211 i,j,k 11 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 212 i,j,k 12 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 213 i,j,k 13 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 214 i,j,k 14 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 215 i,j,k 15 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 216 i,j,k 16 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 217 i,j,k 17 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 218 i,j,k 18 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 219 i,j,k 19 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 220 i,j,k 20 1 1 domain 1 169 QTY_MICROZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 221 i,j,k 1 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 222 i,j,k 2 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 223 i,j,k 3 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 224 i,j,k 4 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 225 i,j,k 5 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 226 i,j,k 6 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 227 i,j,k 7 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 228 i,j,k 8 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 229 i,j,k 9 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 230 i,j,k 10 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 231 i,j,k 11 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 232 i,j,k 12 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 233 i,j,k 13 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 234 i,j,k 14 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 235 i,j,k 15 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 236 i,j,k 16 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 237 i,j,k 17 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 238 i,j,k 18 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 239 i,j,k 19 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 240 i,j,k 20 1 1 domain 1 167 QTY_MESOZOOPLANKTON_CARBON Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 241 i,j,k 1 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 242 i,j,k 2 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 243 i,j,k 3 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 244 i,j,k 4 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 245 i,j,k 5 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 246 i,j,k 6 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 247 i,j,k 7 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 248 i,j,k 8 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 249 i,j,k 9 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 250 i,j,k 10 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 251 i,j,k 11 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 252 i,j,k 12 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 253 i,j,k 13 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 254 i,j,k 14 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 255 i,j,k 15 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 256 i,j,k 16 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 257 i,j,k 17 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 258 i,j,k 18 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 259 i,j,k 19 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 260 i,j,k 20 1 1 domain 1 383 QTY_COLUMN_DEPTH Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 261 i,j,k 1 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 262 i,j,k 2 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 263 i,j,k 3 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 264 i,j,k 4 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 265 i,j,k 5 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 266 i,j,k 6 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 267 i,j,k 7 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 268 i,j,k 8 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 269 i,j,k 9 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 270 i,j,k 10 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 271 i,j,k 11 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 272 i,j,k 12 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 273 i,j,k 13 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 274 i,j,k 14 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 275 i,j,k 15 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 276 i,j,k 16 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 277 i,j,k 17 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 278 i,j,k 18 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 279 i,j,k 19 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 280 i,j,k 20 1 1 domain 2 385 QTY_PARAM_AUTOTROPH1_KDOP Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 281 i,j,k 1 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 282 i,j,k 2 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 283 i,j,k 3 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 284 i,j,k 4 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 285 i,j,k 5 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 286 i,j,k 6 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 287 i,j,k 7 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 288 i,j,k 8 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 289 i,j,k 9 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 290 i,j,k 10 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 291 i,j,k 11 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 292 i,j,k 12 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 293 i,j,k 13 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 294 i,j,k 14 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 295 i,j,k 15 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 296 i,j,k 16 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 297 i,j,k 17 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 298 i,j,k 18 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 299 i,j,k 19 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level - 300 i,j,k 20 1 1 domain 2 387 QTY_PARAM_AUTOTROPH1_KNH4 Lon/Lat(deg): 296.00000000 31.00000000 Vert: 1.000000 level diff --git a/models/MARBL_param_estimation/work/quickbuild.sh b/models/MARBL_param_estimation/work/quickbuild.sh deleted file mode 100755 index 58f81c13a2..0000000000 --- a/models/MARBL_param_estimation/work/quickbuild.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash - -# DART software - Copyright UCAR. This open source software is provided -# by UCAR, "as is", without charge, subject to all terms of use at -# http://www.image.ucar.edu/DAReS/DART/DART_download - -main() { - -export DART=$(git rev-parse --show-toplevel) -source "$DART"/build_templates/buildfunctions.sh - -MODEL=MARBL_param_estimation -LOCATION=threed_sphere - - -programs=( -closest_member_tool -filter -model_mod_check -perfect_model_obs -) - -serial_programs=( -create_fixed_network_seq -create_obs_sequence -fill_inflation_restart -integrate_model -obs_common_subset -obs_diag -obs_sequence_tool -) - -model_programs=( -) - -model_serial_programs=( -) - -# quickbuild arguments -arguments "$@" - -# clean the directory -\rm -f -- *.o *.mod Makefile .cppdefs - -# build any NetCDF files from .cdl files -cdl_to_netcdf - -# build and run preprocess before making any other DART executables -buildpreprocess - -# build -buildit - -# clean up -\rm -f -- *.o *.mod - -} - -main "$@" diff --git a/models/MARBL_state_estimation/model_mod.f90 b/models/MARBL_state_estimation/model_mod.f90 deleted file mode 100644 index 9c347a6daa..0000000000 --- a/models/MARBL_state_estimation/model_mod.f90 +++ /dev/null @@ -1,652 +0,0 @@ -! DART software - Copyright UCAR. This open source software is provided -! by UCAR, "as is", without charge, subject to all terms of use at -! http://www.image.ucar.edu/DAReS/DART/DART_download -! - -module model_mod - -! This is a template showing the interfaces required for a model to be compliant -! with the DART data assimilation infrastructure. Do not change the arguments -! for the public routines. - -use types_mod, only : r8, i8, MISSING_R8, vtablenamelength - -use time_manager_mod, only : time_type, set_time - -use location_mod, only : location_type, get_close_type, & - loc_get_close_obs => get_close_obs, & - loc_get_close_state => get_close_state, & - set_location, set_location_missing, & - get_location, VERTISLEVEL - -use utilities_mod, only : register_module, error_handler, & - E_ERR, E_MSG, & - nmlfileunit, do_output, do_nml_file, do_nml_term, & - find_namelist_in_file, check_namelist_read, & - to_upper - -use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & - nc_add_global_creation_time, & - nc_begin_define_mode, nc_end_define_mode, & - NF90_MAX_NAME, nc_open_file_readonly, & - nc_get_variable, nc_get_variable_size, nc_close_file - -use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & - get_varid_from_kind, get_dart_vector_index - -use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & - QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & - QTY_LAYER_THICKNESS - -use distributed_state_mod, only: get_state - -use ensemble_manager_mod, only : ensemble_type - -! These routines are passed through from default_model_mod. -! To write model specific versions of these routines -! remove the routine from this use statement and add your code to -! this the file. -use default_model_mod, only : pert_model_copies, write_model_time, & - init_time => fail_init_time, & - init_conditions => fail_init_conditions, & - convert_vertical_obs, convert_vertical_state, adv_1step - -implicit none -private - -! routines required by DART code - will be called from filter and other -! DART executables. -public :: get_model_size, & - get_state_meta_data, & - model_interpolate, & - end_model, & - static_init_model, & - nc_write_model_atts, & - get_close_obs, & - get_close_state, & - pert_model_copies, & - convert_vertical_obs, & - convert_vertical_state, & - read_model_time, & - adv_1step, & - init_time, & - init_conditions, & - shortest_time_between_assimilations, & - write_model_time - - -character(len=256), parameter :: source = "model_mod.f90" -character(len=256), parameter :: ocean_geometry = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/ensemble/baseline/ocean_geometry.nc" -logical :: module_initialized = .false. -integer :: dom_id ! used to access the state structure -integer :: nfields ! number of fields in the state vector -integer :: nz ! the number of vertical layers -integer :: model_size -type(time_type) :: assimilation_time_step -real(r8), parameter :: geolon = 360 - 64.0 -real(r8), parameter :: geolat = 31.0 -real(r8) :: basin_depth(2,2) - -logical, parameter :: debug_interpolation = .false. - -! parameters to be used in specifying the DART internal state -integer, parameter :: modelvar_table_height = 13 -integer, parameter :: modelvar_table_width = 5 - -! defining the variables that will be read from the namelist -character(len=256) :: template_file -integer :: time_step_days -integer :: time_step_seconds -character(len=vtablenamelength) & - :: model_state_variables(modelvar_table_height * modelvar_table_width) - -namelist /model_nml/ template_file, & - time_step_days, & - time_step_seconds, & - model_state_variables - -contains - -!------------------------------------------------------------------ -! -! Called to do one time initialization of the model. As examples, -! might define information about the model size or model timestep. -! In models that require pre-computed static data, for instance -! spherical harmonic weights, these would also be computed here. - -subroutine static_init_model() - -integer :: iunit, io -character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width) -integer :: state_qty_list(modelvar_table_height) -real(r8):: state_clamp_vals(modelvar_table_height, 2) -logical :: update_var_list(modelvar_table_height) - -module_initialized = .true. - -! Print module information to log file and stdout. -call register_module(source) - -! Read values from the namelist - -call find_namelist_in_file("input.nml", "model_nml", iunit) -read(iunit, nml = model_nml, iostat = io) - -call check_namelist_read(iunit, io, "model_nml") - -! Record the namelist values used for the run -if (do_nml_file()) write(nmlfileunit, nml=model_nml) -if (do_nml_term()) write( * , nml=model_nml) - -! This time is both the minimum time you can ask the model to advance -! (for models that can be advanced by filter) and it sets the assimilation -! window. All observations within +/- 1/2 this interval from the current -! model time will be assimilated. If this is not settable at runtime -! feel free to hardcode it and remove from the namelist. -assimilation_time_step = set_time(time_step_seconds, & - time_step_days) - -call verify_state_variables(model_state_variables, nfields, variable_table, & - state_qty_list, state_clamp_vals, update_var_list) - -! print *, "variable_table = ",variable_table -! print *, "state_qty_list = ",state_qty_list -! print *, "state_clamp_vals = ",state_clamp_vals -! print *, "update_var_list = ",update_var_list - -dom_id = add_domain(template_file, nfields, & - var_names = variable_table(1:nfields, 1), & - kind_list = state_qty_list(1:nfields), & - clamp_vals = state_clamp_vals, & - update_list = update_var_list(1:nfields)) - -model_size = get_domain_size(dom_id) - -call read_num_layers ! setting the value of nz -call read_ocean_geometry ! determining the basin depth - -end subroutine static_init_model - -!------------------------------------------------------------------ -! Reads the simulation length from a netCDF file. - -function read_model_time(filename) - -character(len=*), intent(in) :: filename -type(time_type) :: read_model_time - -integer :: ncid -character(len=*), parameter :: routine = 'read_model_time' -real(r8) :: days -type(time_type) :: mom6_time -integer :: mom_base_date_in_days, mom_days - -mom_base_date_in_days = 139157 ! 1982 1 1 0 0 -ncid = nc_open_file_readonly(filename, routine) - -call nc_get_variable(ncid, 'Time', days, routine) - -call nc_close_file(ncid, routine) - -mom_days = int(days) + mom_base_date_in_days - -read_model_time = set_time(0,mom_days) - -end function read_model_time - -!------------------------------------------------------------------ -! Returns the number of items in the state vector as an integer. - -function get_model_size() - -integer(i8) :: get_model_size - -if ( .not. module_initialized ) call static_init_model - -get_model_size = get_domain_size(dom_id) - -end function get_model_size - -!------------------------------------------------------------------ -! Given a state handle, a location, and a state quantity, -! interpolates the state variable fields to that location and returns -! the values in expected_obs. The istatus variables should be returned as -! 0 unless there is some problem in computing the interpolation in -! which case a positive istatus should be returned. -! -! For applications in which only perfect model experiments -! with identity observations (i.e. only the value of a particular -! state variable is observed), this can be a NULL INTERFACE. - -subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus) - -type(ensemble_type), intent(in) :: state_handle -integer, intent(in) :: ens_size -type(location_type), intent(in) :: location -integer, intent(in) :: qty -real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values -integer, intent(out) :: istatus(ens_size) - -integer :: qty_id, thickness_id, layer_index -integer(i8) :: qty_index, thickness_index, ens_index -real(8) :: requested_depth, layerdepth_bottom, layerdepth_center, & - layerdepth_top, depth_below, depth_above, val_below, val_above -real(8) :: layer_thicknesses(nz, ens_size) -real(8) :: state_slice(ens_size) -real(8) :: loc_temp(3) - -if ( .not. module_initialized ) call static_init_model - -qty_id = get_varid_from_kind(dom_id, qty) - -! extracting the requested depth value from `location`. -loc_temp = get_location(location) -requested_depth = loc_temp(3) - -if(debug_interpolation) then; print *, "REQUESTED DEPTH = ",requested_depth; end if - -! extracting the current layer thicknesses for each ensemble member. -thickness_id = get_varid_from_kind(dom_id, QTY_LAYER_THICKNESS) - -do layer_index = 1, nz - ! layer thicknesses are always extracted from the grid cell at index (1, 1), since the four grid - ! cells are supposed to represent identical columns. - thickness_index = get_dart_vector_index(1, 1, layer_index, dom_id, thickness_id) - layer_thicknesses(layer_index, :) = get_state(thickness_index, state_handle) -end do - -! performing the interpolation for each ensemble member individually. -do ens_index = 1, ens_size - if(debug_interpolation) then - print *, "BASIN DEPTH = ",-basin_depth(1,1) - print *, "----------------------------------------------------" - print *, "computing centers of layers" - print *, "----------------------------------------------------" - end if - - ! locating the layer index to be used as the upper interpolation point for this ensemble member. - layer_index = nz - layerdepth_bottom = -basin_depth(1,1) ! depth at bottom of the layer given by layer_index. - layerdepth_center = layerdepth_bottom & ! depth at center of the layer given by layer_index. - + .5*layer_thicknesses(layer_index, ens_index) - layerdepth_top = layerdepth_bottom & ! depth at top of the layer given by layer_index. - + layer_thicknesses(layer_index, ens_index) - - if(debug_interpolation) then - print *, "layer = ",layer_index,", center = ",layerdepth_center,", bottom = ",layerdepth_bottom,", top = ",layerdepth_top - end if - - do while((layerdepth_center < requested_depth) .and. (layer_index > 1)) - layer_index = layer_index - 1 - layerdepth_bottom = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) - layerdepth_center = layerdepth_bottom + 0.5 * layer_thicknesses(layer_index, ens_index) - layerdepth_top = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) - - if(debug_interpolation) then - print *, "layer = ",layer_index,", bottom = ",layerdepth_bottom,", center = ",layerdepth_center,", top = ",layerdepth_top - end if - - end do - - ! having located the index of the upper interpolation layer, we now calculate the interpolation. - if((requested_depth < -basin_depth(1,1)) .or. (layerdepth_top < requested_depth)) then - ! case where the requested depth is below the ocean floor, or above the ocean surface - - if(debug_interpolation) then - print *, "----------------------------------------------------" - print *, "depth is below ocean floor or above ocean surface" - print *, "----------------------------------------------------" - end if - - istatus(ens_index) = 1 - expected_obs(ens_index) = MISSING_R8 - - else if((layer_index == nz) .or. (layerdepth_center < requested_depth)) then - ! case where the requested depth is either in the bottom half of the deepest layer, - ! or the top half of the shallowest layer. In both cases, the "interpolated" value is - ! simply the current value of that layer in MOM6. - - if(debug_interpolation) then - print *, "----------------------------------------------------" - print *, "only using value from layer ",layer_index - print *, "----------------------------------------------------" - end if - - istatus(ens_index) = 0 - qty_index = get_dart_vector_index(1, 1, layer_index, dom_id, qty_id) - state_slice = get_state(qty_index, state_handle) - expected_obs(ens_index) = state_slice(ens_index) - - if(debug_interpolation) then; print *, "final value = ",expected_obs(ens_index); end if - - else - ! case where the requested depth is above the center of some layer, and below - ! the center of another. We interpolate linearly between the nearest layers above - ! and below. - - if(debug_interpolation) then - print *, "----------------------------------------------------" - print *, "interpolating between layers ",layer_index," and ",(layer_index + 1) - end if - - istatus(ens_index) = 0 - - ! computing the depths at the centers of the nearest layers above and below - depth_above = layerdepth_center - depth_below = layerdepth_top - layer_thicknesses(layer_index, ens_index) & - - .5*layer_thicknesses(layer_index + 1, ens_index) - - ! extracting the quantity values at the layers above and below - qty_index = get_dart_vector_index(1, 1, layer_index, dom_id, qty_id) - state_slice = get_state(qty_index, state_handle) - val_above = state_slice(ens_index) - - qty_index = get_dart_vector_index(1, 1, layer_index + 1, dom_id, qty_id) - state_slice = get_state(qty_index, state_handle) - val_below = state_slice(ens_index) - - if(debug_interpolation) then - print *, "corresponding to the values: ",val_above," and ",val_below - print *, "----------------------------------------------------" - end if - - ! linear interpolation - expected_obs(ens_index) = val_above + (requested_depth - depth_above) * (val_below - val_above) / (depth_below - depth_above) - - if(debug_interpolation) then; print *, "final value = ",expected_obs(ens_index); end if - end if -end do - -end subroutine model_interpolate - - - -!------------------------------------------------------------------ -! Returns the smallest increment in time that the model is capable -! of advancing the state in a given implementation, or the shortest -! time you want the model to advance between assimilations. - -function shortest_time_between_assimilations() - -type(time_type) :: shortest_time_between_assimilations - -if ( .not. module_initialized ) call static_init_model - -shortest_time_between_assimilations = assimilation_time_step - -end function shortest_time_between_assimilations - - - -!------------------------------------------------------------------ -! Given an integer index into the state vector, returns the -! associated location and optionally the physical quantity. - -subroutine get_state_meta_data(index_in, location, qty) - -integer(i8), intent(in) :: index_in -type(location_type), intent(out) :: location -integer, intent(out), optional :: qty - -real(r8) :: lat, lon -integer :: lon_index, lat_index, level, local_qty - -if ( .not. module_initialized ) call static_init_model - -call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) - -location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) - -if (present(qty)) then - qty = local_qty -endif - - -end subroutine get_state_meta_data - - -!------------------------------------------------------------------ -! Any model specific distance calcualtion can be done here -subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & - num_close, close_ind, dist, ens_handle) - -type(get_close_type), intent(in) :: gc ! handle to a get_close structure -integer, intent(in) :: base_type ! observation TYPE -type(location_type), intent(inout) :: base_loc ! location of interest -type(location_type), intent(inout) :: locs(:) ! obs locations -integer, intent(in) :: loc_qtys(:) ! QTYS for obs -integer, intent(in) :: loc_types(:) ! TYPES for obs -integer, intent(out) :: num_close ! how many are close -integer, intent(out) :: close_ind(:) ! incidies into the locs array -real(r8), optional, intent(out) :: dist(:) ! distances in radians -type(ensemble_type), optional, intent(in) :: ens_handle - -character(len=*), parameter :: routine = 'get_close_obs' - -call loc_get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & - num_close, close_ind, dist, ens_handle) - -end subroutine get_close_obs - - -!------------------------------------------------------------------ -! Any model specific distance calcualtion can be done here -subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & - num_close, close_ind, dist, ens_handle) - -type(get_close_type), intent(in) :: gc ! handle to a get_close structure -type(location_type), intent(inout) :: base_loc ! location of interest -integer, intent(in) :: base_type ! observation TYPE -type(location_type), intent(inout) :: locs(:) ! state locations -integer, intent(in) :: loc_qtys(:) ! QTYs for state -integer(i8), intent(in) :: loc_indx(:) ! indices into DART state vector -integer, intent(out) :: num_close ! how many are close -integer, intent(out) :: close_ind(:) ! indices into the locs array -real(r8), optional, intent(out) :: dist(:) ! distances in radians -type(ensemble_type), optional, intent(in) :: ens_handle - -character(len=*), parameter :: routine = 'get_close_state' - - -call loc_get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & - num_close, close_ind, dist, ens_handle) - - -end subroutine get_close_state - - -!------------------------------------------------------------------ -! Does any shutdown and clean-up needed for model. Can be a NULL -! INTERFACE if the model has no need to clean up storage, etc. - -subroutine end_model() - - -end subroutine end_model - - -!------------------------------------------------------------------ -! write any additional attributes to the output and diagnostic files - -subroutine nc_write_model_atts(ncid, domain_id) - -integer, intent(in) :: ncid ! netCDF file identifier -integer, intent(in) :: domain_id - -if ( .not. module_initialized ) call static_init_model - -! put file into define mode. - -call nc_begin_define_mode(ncid) - -call nc_add_global_creation_time(ncid) - -call nc_add_global_attribute(ncid, "model_source", source ) -call nc_add_global_attribute(ncid, "model", "template") - -call nc_end_define_mode(ncid) - -! Flush the buffer and leave netCDF file open -call nc_synchronize_file(ncid) - -end subroutine nc_write_model_atts - -!------------------------------------------------------------------ -! Verify that the namelist was filled in correctly, and check -! that there are valid entries for the dart_kind. -! Returns a table with columns: -! -! netcdf_variable_name ; dart_qty_string ; update_string - -subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp_vals, update_var) - -character(len=*), intent(inout) :: state_variables(:) -integer, intent(out) :: ngood -character(len=*), intent(out) :: table(:,:) -integer, intent(out) :: qty_list(:) ! kind number -real(r8), intent(out) :: clamp_vals(:,:) -logical, intent(out) :: update_var(:) ! logical update - -integer :: nrows, i -character(len=NF90_MAX_NAME) :: varname, dartstr, lowerbound, upperbound, update -character(len=256) :: string1, string2 - -if ( .not. module_initialized ) call static_init_model - -nrows = size(table,1) - -ngood = 0 - -MyLoop : do i = 1, nrows - - varname = trim(state_variables(5*i -4)) - dartstr = trim(state_variables(5*i -3)) - lowerbound = trim(state_variables(5*i -2)) - upperbound = trim(state_variables(5*i -1)) - update = trim(state_variables(5*i )) - - call to_upper(update) - - table(i,1) = trim(varname) - table(i,2) = trim(dartstr) - table(i,3) = trim(lowerbound) - table(i,4) = trim(upperbound) - table(i,5) = trim(update) - - if ( table(i,1) == ' ' .and. table(i,2) == ' ' .and. table(i,3) == ' ' .and. table(i,4) == ' ' .and. table(i,5) == ' ') exit MyLoop ! Found end of list. - - if ( table(i,1) == ' ' .or. table(i,2) == ' ' .or. table(i,3) == ' ' .or. table(i,4) == ' ' .or. table(i,5) == ' ') then - string1 = 'model_nml:model_state_variables not fully specified' - call error_handler(E_ERR,'verify_state_variables',string1) - endif - - ! Make sure DART qty is valid - - qty_list(i) = get_index_for_quantity(dartstr) - if( qty_list(i) < 0 ) then - write(string1,'(''there is no obs_kind <'',a,''> in obs_kind_mod.f90'')') trim(dartstr) - call error_handler(E_ERR,'verify_state_variables',string1) - endif - - ! Make sure the update variable has a valid name - - select case (update) - case ('UPDATE') - update_var(i) = .true. - case ('NO_COPY_BACK') - update_var(i) = .false. - case default - write(string1,'(A)') 'only UPDATE or NO_COPY_BACK supported in model_state_variable namelist' - write(string2,'(6A)') 'you provided : ', trim(varname), ', ', trim(dartstr), ', ', trim(update) - call error_handler(E_ERR,'verify_state_variables',string1, text2=string2) - end select - - ! reading the clamp values - - if (table(i, 3) /= 'NA') then - read(table(i,3), '(d16.8)') clamp_vals(i,1) - else - clamp_vals(i,1) = MISSING_R8 - endif - - if (table(i,4) /= 'NA') then - read(table(i,4), '(d16.8)') clamp_vals(i,2) - else - clamp_vals(i,2) = MISSING_R8 - endif - - ngood = ngood + 1 -enddo MyLoop - - -end subroutine verify_state_variables - -!------------------------------------------------------------ -function on_v_grid(qty) - -integer, intent(in) :: qty -logical :: on_v_grid - -if (qty == QTY_V_CURRENT_COMPONENT) then - on_v_grid = .true. -else - on_v_grid = .false. -endif - -end function on_v_grid - -!---------------------------------------------------------- -function on_u_grid(qty) - -integer, intent(in) :: qty -logical :: on_u_grid - -if (qty == QTY_U_CURRENT_COMPONENT) then - on_u_grid = .true. -else - on_u_grid = .false. -endif - -end function on_u_grid - -!------------------------------------------------------------ -! Read number of vertical layers from mom6 template file -subroutine read_num_layers() - -integer :: ncid - -character(len=*), parameter :: routine = 'read_num_layers' - -ncid = nc_open_file_readonly(template_file) - -call nc_get_variable_size(ncid, 'Layer', nz) - -call nc_close_file(ncid) - -end subroutine read_num_layers - -!------------------------------------------------------------ -! ocean_geom are 2D state sized static data -! HK Do these arrays become too big in high res cases? -subroutine read_ocean_geometry() - -integer :: ncid - -character(len=*), parameter :: routine = 'read_ocean_geometry' - -! Need nx, ny -if ( .not. module_initialized ) call static_init_model - -ncid = nc_open_file_readonly(ocean_geometry) - -call nc_get_variable(ncid, 'D', basin_depth, routine) - -call nc_close_file(ncid) - -end subroutine read_ocean_geometry - -!=================================================================== -! End of model_mod -!=================================================================== -end module model_mod - diff --git a/models/MARBL_state_estimation/readme.rst b/models/MARBL_state_estimation/readme.rst deleted file mode 100644 index 40d5ce4be0..0000000000 --- a/models/MARBL_state_estimation/readme.rst +++ /dev/null @@ -1,5 +0,0 @@ -MARBL_state_estimation -======================= - -.. attention:: - Add your model documentation here. diff --git a/models/MARBL_state_estimation/work/input.nml b/models/MARBL_state_estimation/work/input.nml deleted file mode 100644 index 2eea5790a3..0000000000 --- a/models/MARBL_state_estimation/work/input.nml +++ /dev/null @@ -1,238 +0,0 @@ -&perfect_model_obs_nml - read_input_state_from_file = .true., - single_file_in = .false., - input_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/RESTART/DART_perfect_model_obs/MOM.res.nc", - - write_output_state_to_file = .true., - single_file_out = .false., - output_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/RESTART/DART_perfect_model_obs/MOM.res.output.nc", - output_interval = 1, - - async = 0, - adv_ens_command = "./advance_model.csh", - - obs_seq_in_file_name = "obs_seq.in", - obs_seq_out_file_name = "obs_seq.out", - init_time_days = 0, - init_time_seconds = 0, - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, - - trace_execution = .false., - output_timestamps = .false., - print_every_nth_obs = -1, - output_forward_op_errors = .false., - silence = .false., - / - -&filter_nml - single_file_in = .false., - input_state_files = '', - input_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/DART/ensemble_members.txt', - - stages_to_write = 'preassim', 'analysis', 'output', - - single_file_out = .false., - output_state_files = '', - output_state_file_list = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/DART/ensemble_members.txt', - output_interval = 1, - output_members = .true., - num_output_state_members = 80, - output_mean = .true., - output_sd = .true., - write_all_stages_at_end = .true., - - ens_size = 80, - num_groups = 1, - perturb_from_single_instance = .false., - perturbation_amplitude = 1e-2, - distributed_state = .true., - - async = 0, - adv_ens_command = "./advance_model.csh", - - obs_sequence_in_name ='/glade/u/home/rarmstrong/work/BATS_state_estimation_obsseq/BATS_state_estimation_147976.out', - obs_sequence_out_name ='/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/output/147976/obs_seq.final', - num_output_obs_members = 80, - init_time_days = -1, - init_time_seconds = -1, - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, - - inf_flavor = 5, 0, - inf_initial_from_restart = .true., .false., - inf_sd_initial_from_restart = .true., .false., - inf_deterministic = .true., .true., - inf_initial = 1.0, 1.0, - inf_lower_bound = 0.0, 1.0, - inf_upper_bound = 100.0, 1000000.0, - inf_damping = 0.9, 1.0, - inf_sd_initial = 0.6, 0.0, - inf_sd_lower_bound = 0.6, 0.0, - inf_sd_max_change = 1.05, 1.05, - - trace_execution = .true., - output_timestamps = .false., - output_forward_op_errors = .false., - silence = .false., - / - -&fill_inflation_restart_nml - write_prior_inf = .true., - prior_inf_mean = 1.0, - prior_inf_sd = 0.6, - - write_post_inf = .false., - post_inf_mean = 1.00, - post_inf_sd = 0.6, - - input_state_files = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/ensemble/member_0001/RESTART/MOM.res.nc', - single_file = .false., - verbose = .false. - / - - -&ensemble_manager_nml - / - -&assim_tools_nml - filter_kind = 1, - cutoff = 1000000.0 - sort_obs_inc = .false., - spread_restoration = .false., - sampling_error_correction = .false., - adaptive_localization_threshold = -1, - distribute_mean = .false. - output_localization_diagnostics = .false., - localization_diagnostics_file = 'localization_diagnostics', - print_every_nth_obs = 0 - / - -&cov_cutoff_nml - select_localization = 1 - / - -®_factor_nml - select_regression = 1, - input_reg_file = "time_mean_reg", - save_reg_diagnostics = .false., - reg_diagnostics_file = "reg_diagnostics" - / - -&obs_sequence_nml - write_binary_obs_sequence = .false. - / - -&obs_kind_nml - assimilate_these_obs_types = 'POLY_ELECTRODE_OXYGEN', - 'TITRATION_ALKALINITY', - 'CATALYTIC_CARBON', - 'UV_OXY_NITROGEN', - 'CFA_SILICATE', - 'CFA_PHOSPHATE', - 'CFA_NITRATE' - evaluate_these_obs_types = '' - / - -&model_nml - template_file = '/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_state_estimation/ensemble/member_0001/RESTART/MOM.res.nc', - time_step_days = 1, - time_step_seconds = 0, - model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', - 'SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', - 'PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', - 'Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', - 'DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', - 'O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', - 'DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', - 'DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', - 'DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', - 'ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', - 'microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' - / - -&utilities_nml - TERMLEVEL = 1, - module_details = .false., - logfilename = 'dart_log.out', - nmlfilename = 'dart_log.nml', - write_nml = 'none' - / - -&preprocess_nml - input_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/DEFAULT_obs_def_mod.F90' - output_obs_def_mod_file = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_mod.f90' - input_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' - output_obs_qty_mod_file = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/obs_kind_mod.f90' - obs_type_files = '/glade/work/rarmstrong/DART/observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '/glade/work/rarmstrong/DART/assimilation_code/modules/observations/default_quantities_mod.f90' - / - -&obs_sequence_tool_nml - filename_seq = 'obs_seq.one', 'obs_seq.two', - filename_out = 'obs_seq.processed', - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, - print_only = .false., - gregorian_cal = .false. - / - -&obs_diag_nml - obs_sequence_name = '' - obs_sequence_list = 'obs_diag_files/obs_seq_list.txt' - first_bin_center = 2005, 2, 24, 0, 0, 0 - last_bin_center = 2006, 2, 22, 0, 0, 0 - bin_separation = 0, 0, 1, 0, 0, 0 - bin_width = 0, 0, 1, 0, 0, 0 - time_to_skip = 0, 0, 0, 0, 0, 0 - max_num_bins = 1000 - plevel = -888888.0 - hlevel = -1, -5, -10, -50, -100, -250, -500, -1000, -2000, -3000, -4000, -5000, -6000 - mlevel = -888888 - plevel_edges = -888888.0 - hlevel_edges = -888888.0 - mlevel_edges = -888888 - Nregions = 1 - lonlim1 = 0 - lonlim2 = 360 - latlim1 = -90 - latlim2 = 90 - reg_names = 'null' - trusted_obs = 'null' - create_rank_histogram = .true. - outliers_in_histogram = .false. - use_zero_error_obs = .false. - verbose = .false. - / - -&state_vector_io_nml - / - -&model_mod_check_nml - input_state_files = '../ensemble/baseline/RESTART/MOM.res.nc' - output_state_files = 'testing/model_mod_check_output/output.nc' - test1thru = 0, - run_tests = 1,2,3,4,5,6,7 - x_ind = 261 - loc_of_interest = 296.0, 31.0, -200.0 - quantity_of_interest = 'QTY_DISSOLVED_ORGANIC_CARBON' - interp_test_dx = 0.02 - interp_test_xrange = 0.0, 1.0 - verbose = .true. - / - -&quality_control_nml - input_qc_threshold = 3.0, - outlier_threshold = 3.0, -/ - -&location_nml - / diff --git a/models/MARBL_state_estimation/work/quickbuild.sh b/models/MARBL_state_estimation/work/quickbuild.sh deleted file mode 100755 index 75cf123146..0000000000 --- a/models/MARBL_state_estimation/work/quickbuild.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash - -# DART software - Copyright UCAR. This open source software is provided -# by UCAR, "as is", without charge, subject to all terms of use at -# http://www.image.ucar.edu/DAReS/DART/DART_download - -main() { - -export DART=$(git rev-parse --show-toplevel) -source "$DART"/build_templates/buildfunctions.sh - -MODEL=MARBL_state_estimation -LOCATION=threed_sphere - - -programs=( -closest_member_tool -filter -model_mod_check -perfect_model_obs -) - -serial_programs=( -create_fixed_network_seq -create_obs_sequence -fill_inflation_restart -integrate_model -obs_common_subset -obs_diag -obs_sequence_tool -) - -model_programs=( -) - -model_serial_programs=( -) - -# quickbuild arguments -arguments "$@" - -# clean the directory -\rm -f -- *.o *.mod Makefile .cppdefs - -# build any NetCDF files from .cdl files -cdl_to_netcdf - -# build and run preprocess before making any other DART executables -buildpreprocess - -# build -buildit - -# clean up -\rm -f -- *.o *.mod - -} - -main "$@" From 5123c9dfb1996d7c7ec36a6557268a1d74892075 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 09:00:38 -0600 Subject: [PATCH 21/35] Changed model name Replaced model directory 'MARBL_joint_estimation' with 'MARBL_column' and compiled to make sure the code works --- models/{MARBL_joint_estimation => MARBL_column}/model_mod.f90 | 0 models/{MARBL_joint_estimation => MARBL_column}/readme.rst | 0 models/{MARBL_joint_estimation => MARBL_column}/work/input.nml | 0 .../{MARBL_joint_estimation => MARBL_column}/work/quickbuild.sh | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename models/{MARBL_joint_estimation => MARBL_column}/model_mod.f90 (100%) rename models/{MARBL_joint_estimation => MARBL_column}/readme.rst (100%) rename models/{MARBL_joint_estimation => MARBL_column}/work/input.nml (100%) rename models/{MARBL_joint_estimation => MARBL_column}/work/quickbuild.sh (96%) diff --git a/models/MARBL_joint_estimation/model_mod.f90 b/models/MARBL_column/model_mod.f90 similarity index 100% rename from models/MARBL_joint_estimation/model_mod.f90 rename to models/MARBL_column/model_mod.f90 diff --git a/models/MARBL_joint_estimation/readme.rst b/models/MARBL_column/readme.rst similarity index 100% rename from models/MARBL_joint_estimation/readme.rst rename to models/MARBL_column/readme.rst diff --git a/models/MARBL_joint_estimation/work/input.nml b/models/MARBL_column/work/input.nml similarity index 100% rename from models/MARBL_joint_estimation/work/input.nml rename to models/MARBL_column/work/input.nml diff --git a/models/MARBL_joint_estimation/work/quickbuild.sh b/models/MARBL_column/work/quickbuild.sh similarity index 96% rename from models/MARBL_joint_estimation/work/quickbuild.sh rename to models/MARBL_column/work/quickbuild.sh index f96b002beb..0e847b5a03 100755 --- a/models/MARBL_joint_estimation/work/quickbuild.sh +++ b/models/MARBL_column/work/quickbuild.sh @@ -9,7 +9,7 @@ main() { export DART=$(git rev-parse --show-toplevel) source "$DART"/build_templates/buildfunctions.sh -MODEL=MARBL_joint_estimation +MODEL=MARBL_column LOCATION=threed_sphere From d787fcb191d228b1fc079c2c34309c59a7c23597 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 10:53:40 -0600 Subject: [PATCH 22/35] Station location is now a namelist option Removed the hard-coded location of BATS station and added it as `station_location` in the input.nml This allows the users to run the code for any location on earth (i.e., it doesn't have to be Bermuda station). I also cleaned up the input.nml and stripped out the old path names to Robin's directories. --- models/MARBL_column/model_mod.f90 | 24 +++-- models/MARBL_column/work/input.nml | 167 +++++++++++++++-------------- 2 files changed, 104 insertions(+), 87 deletions(-) diff --git a/models/MARBL_column/model_mod.f90 b/models/MARBL_column/model_mod.f90 index c9d0fdfc17..732c158d99 100644 --- a/models/MARBL_column/model_mod.f90 +++ b/models/MARBL_column/model_mod.f90 @@ -83,8 +83,8 @@ module model_mod integer :: nz ! the number of vertical layers integer :: model_size type(time_type) :: assimilation_time_step -real(r8), parameter :: geolon = 360 - 64.0 -real(r8), parameter :: geolat = 31.0 +real(r8) :: geolon +real(r8) :: geolat real(r8) :: basin_depth(2,2) ! parameters to be used in specifying the DART internal state @@ -96,6 +96,7 @@ module model_mod ! defining the variables that will be read from the namelist character(len=256) :: template_file(2) character(len=256) :: ocean_geometry +real(r8) :: station_location(2) integer :: time_step_days integer :: time_step_seconds logical :: estimate_params @@ -104,12 +105,13 @@ module model_mod character(len=vtablenamelength) & :: model_parameters(modelparams_table_height * modelparams_table_width) -namelist /model_nml/ template_file, & - ocean_geometry, & - time_step_days, & - time_step_seconds, & +namelist /model_nml/ template_file, & + ocean_geometry, & + station_location, & + time_step_days, & + time_step_seconds, & model_state_variables, & - estimate_params, & + estimate_params, & model_parameters contains @@ -390,13 +392,18 @@ subroutine get_state_meta_data(index_in, location, qty) type(location_type), intent(out) :: location integer, intent(out), optional :: qty -real(r8) :: lat, lon integer :: lon_index, lat_index, level, local_qty if ( .not. module_initialized ) call static_init_model call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) +! Make sure the longitude is properly assigned +geolon = station_location(1) +geolat = station_location(2) + +if (geolon < 0.0_r8) geolon = 360.0 + geolon + location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) if (present(qty)) then @@ -406,7 +413,6 @@ subroutine get_state_meta_data(index_in, location, qty) end subroutine get_state_meta_data - !------------------------------------------------------------------ ! Any model specific distance calcualtion can be done here subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & diff --git a/models/MARBL_column/work/input.nml b/models/MARBL_column/work/input.nml index b1ddfb5ef1..16bd75f58f 100644 --- a/models/MARBL_column/work/input.nml +++ b/models/MARBL_column/work/input.nml @@ -1,50 +1,55 @@ -&perfect_model_obs_nml - read_input_state_from_file = .true., - single_file_in = .false., - input_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/RESTART/DART_perfect_model_obs/MOM.res.nc", - - write_output_state_to_file = .true., - single_file_out = .false., - output_state_files = "/glade/work/rarmstrong/cesm/cesm2_3_alpha12b+mom6_marbl/components/mom/standalone/examples/single_column_MARBL/BATS_joint_estimation/RESTART/DART_perfect_model_obs/MOM.res.output.nc", - output_interval = 1, - async = 0, - adv_ens_command = "./advance_model.csh", +&probit_transform_nml + / - obs_seq_in_file_name = "obs_seq.in", - obs_seq_out_file_name = "obs_seq.out", - init_time_days = 0, - init_time_seconds = 0, - first_obs_days = -1, - first_obs_seconds = -1, - last_obs_days = -1, - last_obs_seconds = -1, +&algorithm_info_nml + qceff_table_filename = '' + / - trace_execution = .false., - output_timestamps = .false., - print_every_nth_obs = -1, - output_forward_op_errors = .false., - silence = .false., +&model_nml + template_file = 'ensemble/background/member_0001/RESTART/MOM.res.nc', 'ensemble/background/member_0001/marbl_params.nc', + ocean_geometry = 'ensemble/background/member_0001/ocean_geometry.nc', + station_location = -64, 31 + time_step_days = 1, + time_step_seconds = 0, + model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', + 'PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', + 'DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', + 'O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', + 'DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', + 'DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', + 'DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', + 'ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', + 'microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' + estimate_params = .true. + model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE' / +'params_input.txt', +'params_output.txt', + &filter_nml single_file_in = .false., - input_state_files = '', - input_state_file_list = 'states_input.txt', 'params_input.txt', + input_state_files = '', + input_state_file_list = 'states_input.txt', 'params_input.txt' - stages_to_write = 'preassim', 'analysis', 'output', + stages_to_write = 'preassim', 'analysis', 'output', single_file_out = .false., - output_state_files = '', - output_state_file_list = 'states_output.txt', 'params_output.txt', + output_state_files = '', + output_state_file_list = 'states_output.txt', 'params_output.txt' output_interval = 1, output_members = .true., - num_output_state_members = 3, + num_output_state_members = 3, output_mean = .true., output_sd = .true., - write_all_stages_at_end = .true., + write_all_stages_at_end = .true., - ens_size = 3, + ens_size = 3, num_groups = 1, perturb_from_single_instance = .false., perturbation_amplitude = 1e-2, @@ -53,9 +58,9 @@ async = 0, adv_ens_command = "./advance_model.csh", - obs_sequence_in_name ='../../data/obs_seq_files/BATS_147612.out', - obs_sequence_out_name ='obs_seq.final', - num_output_obs_members = 3, + obs_sequence_in_name = 'BATS_147612.out', + obs_sequence_out_name = 'obs_seq.final', + num_output_obs_members = 3, init_time_days = -1, init_time_seconds = -1, first_obs_days = -1, @@ -64,10 +69,10 @@ last_obs_seconds = -1, inf_flavor = 5, 0, - inf_initial_from_restart = .true., .false., + inf_initial_from_restart = .true., .false., inf_sd_initial_from_restart = .true., .false., inf_deterministic = .true., .true., - inf_initial = 1.0, 1.0, + inf_initial = 1.0, 1.0, inf_lower_bound = 0.0, 1.0, inf_upper_bound = 100.0, 1000000.0, inf_damping = 0.9, 1.0, @@ -90,18 +95,53 @@ post_inf_mean = 1.00, post_inf_sd = 0.6, - input_state_files = '../ensemble/background/member_0001/RESTART/MOM.res.nc', '../ensemble/background/member_0001/marbl_params.nc', + input_state_files = 'ensemble/background/member_0001/RESTART/MOM.res.nc', 'ensemble/background/member_0001/marbl_params.nc', single_file = .false., verbose = .false. / +&quality_control_nml + input_qc_threshold = 3.0, + outlier_threshold = 3.0, +/ + +&location_nml + / + +&perfect_model_obs_nml + read_input_state_from_file = .true., + single_file_in = .false., + input_state_files = "MOM.res.nc", + + write_output_state_to_file = .true., + single_file_out = .false., + output_state_files = "MOM.res.output.nc", + output_interval = 1, + + async = 0, + adv_ens_command = "./advance_model.csh", + + obs_seq_in_file_name = "obs_seq.in", + obs_seq_out_file_name = "obs_seq.out", + init_time_days = 0, + init_time_seconds = 0, + first_obs_days = -1, + first_obs_seconds = -1, + last_obs_days = -1, + last_obs_seconds = -1, + + trace_execution = .false., + output_timestamps = .false., + print_every_nth_obs = -1, + output_forward_op_errors = .false., + silence = .false., + / &ensemble_manager_nml / &assim_tools_nml - filter_kind = 1, - cutoff = 1000000.0 + cutoff = 1000000.0, sort_obs_inc = .false., spread_restoration = .false., sampling_error_correction = .false., @@ -131,35 +171,13 @@ assimilate_these_obs_types = 'BATS_OXYGEN', 'BATS_ALKALINITY', 'BATS_INORGANIC_CARBON', - 'BATS_SILICATE', - 'BATS_PHOSPHATE', + 'BATS_SILICATE', + 'BATS_PHOSPHATE', 'BATS_NITRATE' evaluate_these_obs_types = 'BATS_ORGANIC_CARBON', 'BATS_NITROGEN' / -&model_nml - template_file = '../ensemble/background/member_0001/RESTART/MOM.res.nc', '../ensemble/background/member_0001/marbl_params.nc', - ocean_geometry = '../ensemble/background/member_0001/ocean_geometry.nc', - time_step_days = 1, - time_step_seconds = 0, - model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', - 'SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', - 'PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', - 'Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', - 'DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', - 'O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', - 'DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', - 'DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', - 'DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', - 'ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', - 'microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', - 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' - estimate_params = .true. - model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE' - / - &utilities_nml TERMLEVEL = 1, module_details = .false., @@ -174,7 +192,7 @@ input_obs_qty_mod_file = '../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' output_obs_qty_mod_file = '../../../assimilation_code/modules/observations/obs_kind_mod.f90' obs_type_files = '../../../observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '../../../assimilation_code/modules/observations/default_quantities_mod.f90', + quantity_files = '../../../assimilation_code/modules/observations/default_quantities_mod.f90', '../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' / @@ -221,22 +239,15 @@ / &model_mod_check_nml - input_state_files = '../bg_ensemble/baseline/RESTART/MOM.res.nc' - output_state_files = 'testing/model_mod_check_output/output.nc' - test1thru = 0, - run_tests = 1,2,3,4,5,6,7 - x_ind = 261 + input_state_files = 'mom_in.nc', 'param_in.nc' + output_state_files = 'mom_out.nc', 'param_out.nc' + test1thru = 3 + run_tests = 1 + x_ind = 600 loc_of_interest = 1.11, 0.54, -500.0 - quantity_of_interest = 'BATS_NITROGEN' + quantity_of_interest = 'BATS_OXYGEN' interp_test_dx = 0.02 interp_test_xrange = 0.0, 1.0 verbose = .true. / -&quality_control_nml - input_qc_threshold = 3.0, - outlier_threshold = 3.0, -/ - -&location_nml - / From db03d86cac109048faf325293f8c8877fa6dce74 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 11:29:33 -0600 Subject: [PATCH 23/35] Improved the logic of the DA problem The model size is now computed based on the number of active domains. Also, the accessor function get_model_size can now be used from outside the model_mod without the need for local variables. The code as it stands should be able to run: - state estimation only - parameter estimation only - state and parameters estimation --- models/MARBL_column/model_mod.f90 | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/models/MARBL_column/model_mod.f90 b/models/MARBL_column/model_mod.f90 index 732c158d99..a6231457e4 100644 --- a/models/MARBL_column/model_mod.f90 +++ b/models/MARBL_column/model_mod.f90 @@ -1,4 +1,3 @@ -! DART software - Copyright UCAR. This open source software is provided ! by UCAR, "as is", without charge, subject to all terms of use at ! http://www.image.ucar.edu/DAReS/DART/DART_download ! @@ -32,7 +31,8 @@ module model_mod nc_get_variable, nc_get_variable_size, nc_close_file use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & - get_varid_from_kind, get_dart_vector_index + get_varid_from_kind, get_dart_vector_index, & + get_num_domains use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & @@ -124,7 +124,7 @@ module model_mod subroutine static_init_model() -integer :: iunit, io +integer :: iunit, io, i_dom, domain_count character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width), & param_table(modelparams_table_height, modelparams_table_width) integer :: state_qty_list(modelvar_table_height), & @@ -158,6 +158,20 @@ subroutine static_init_model() assimilation_time_step = set_time(time_step_seconds, & time_step_days) +! The kind of experiments that can be performed using this code: +! 1- State estimation: +! To achieve this, you'll need to set "estimate_params" +! in the model_nml to ".false." +! 2- State and Parameters estimation: +! To achieve this, set "estimate_params" to ".true." +! 3- Parameters estimation only: +! To achieve this, we still need to read in the state +! in order to compute covariances and innovations. +! First, set "estimate_params" to ".true." and +! Next, set the 5th column in the state table as +! "NO_COPY_BACK". The parameters update status should +! be kept as "Update" + ! setting up the DART state vector call verify_state_variables(model_state_variables, nfields, variable_table, & state_qty_list, state_clamp_vals, update_var_list) @@ -183,6 +197,14 @@ subroutine static_init_model() call read_num_layers ! setting the value of nz call read_ocean_geometry ! determining the basin depth +! Determine the domain and model size +domain_count = get_num_domains() + +model_size = 0 +do i_dom = 1,domain_count + model_size = model_size + get_domain_size(i_dom) +enddo + end subroutine static_init_model !------------------------------------------------------------------ @@ -221,7 +243,7 @@ function get_model_size() if ( .not. module_initialized ) call static_init_model -get_model_size = get_domain_size(state_dom_id) + get_domain_size(param_dom_id) +get_model_size = model_size end function get_model_size @@ -642,7 +664,6 @@ subroutine read_ocean_geometry() character(len=*), parameter :: routine = 'read_ocean_geometry' -! Need nx, ny if ( .not. module_initialized ) call static_init_model ncid = nc_open_file_readonly(ocean_geometry) From 9772e8ad0be8259506954f86a06b7f7fab702050 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 11:48:09 -0600 Subject: [PATCH 24/35] model-mod clean-up Removed unused routines and unnecessary formatting --- models/MARBL_column/model_mod.f90 | 46 ++----------------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/models/MARBL_column/model_mod.f90 b/models/MARBL_column/model_mod.f90 index a6231457e4..b90543202e 100644 --- a/models/MARBL_column/model_mod.f90 +++ b/models/MARBL_column/model_mod.f90 @@ -403,7 +403,6 @@ function shortest_time_between_assimilations() end function shortest_time_between_assimilations - !------------------------------------------------------------------ ! Given an integer index into the state vector, returns the ! associated location and optionally the physical quantity. @@ -424,7 +423,7 @@ subroutine get_state_meta_data(index_in, location, qty) geolon = station_location(1) geolat = station_location(2) -if (geolon < 0.0_r8) geolon = 360.0 + geolon +if (geolon < 0.0_r8) geolon = 360.0 + geolon location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) @@ -484,17 +483,6 @@ subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & end subroutine get_close_state - -!------------------------------------------------------------------ -! Does any shutdown and clean-up needed for model. Can be a NULL -! INTERFACE if the model has no need to clean up storage, etc. - -subroutine end_model() - - -end subroutine end_model - - !------------------------------------------------------------------ ! write any additional attributes to the output and diagnostic files @@ -594,13 +582,13 @@ subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp ! reading the clamp values if (table(i, 3) /= 'NA') then - read(table(i,3), '(d16.8)') clamp_vals(i,1) + read(table(i,3), *) clamp_vals(i,1) else clamp_vals(i,1) = MISSING_R8 endif if (table(i,4) /= 'NA') then - read(table(i,4), '(d16.8)') clamp_vals(i,2) + read(table(i,4), *) clamp_vals(i,2) else clamp_vals(i,2) = MISSING_R8 endif @@ -611,34 +599,6 @@ subroutine verify_state_variables(state_variables, ngood, table, qty_list, clamp end subroutine verify_state_variables -!------------------------------------------------------------ -function on_v_grid(qty) - -integer, intent(in) :: qty -logical :: on_v_grid - -if (qty == QTY_V_CURRENT_COMPONENT) then - on_v_grid = .true. -else - on_v_grid = .false. -endif - -end function on_v_grid - -!---------------------------------------------------------- -function on_u_grid(qty) - -integer, intent(in) :: qty -logical :: on_u_grid - -if (qty == QTY_U_CURRENT_COMPONENT) then - on_u_grid = .true. -else - on_u_grid = .false. -endif - -end function on_u_grid - !------------------------------------------------------------ ! Read number of vertical layers from mom6 template file subroutine read_num_layers() From 99fd5dce8b05a55612836b6f2aa418327f8c6267 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 13:35:24 -0600 Subject: [PATCH 25/35] Updated QTYs of parameters I removed the QTYs associated with specific parameters and added a single definition: 'QTY_BGC_PARAM' The changes are now reflected in the default_quantities_mod Did some cleaning in the model-mod and changed some configuration in the input.nml file to be able to run the interpolation test --- .../observations/default_quantities_mod.f90 | 17 +++++ .../observations/ocean_quantities_mod.f90 | 38 +---------- models/MARBL_column/model_mod.f90 | 63 ++++++++++--------- models/MARBL_column/work/input.nml | 8 +-- 4 files changed, 54 insertions(+), 72 deletions(-) diff --git a/assimilation_code/modules/observations/default_quantities_mod.f90 b/assimilation_code/modules/observations/default_quantities_mod.f90 index 531116c603..2e8cd2278f 100644 --- a/assimilation_code/modules/observations/default_quantities_mod.f90 +++ b/assimilation_code/modules/observations/default_quantities_mod.f90 @@ -387,6 +387,23 @@ ! QTY_WIND_TURBINE_POWER ! QTY_W_CURRENT_COMPONENT ! QTY_X_LAMBDA +! QTY_NITRATE_CONCENTRATION +! QTY_PHOSPHATE_CONCENTRATION +! QTY_DISSOLVED_OXYGEN +! QTY_PHYTOPLANKTON_BIOMASS +! QTY_ALKALINITY +! QTY_DISSOLVED_INORGANIC_CARBON +! QTY_DISSOLVED_ORGANIC_CARBON +! QTY_DISSOLVED_ORGANIC_NITROGEN +! QTY_DISSOLVED_ORGANIC_P +! QTY_DISSOLVED_INORGANIC_IRON +! QTY_SURFACE_CHLOROPHYLL +! QTY_LAYER_THICKNESS +! QTY_COLUMN_DEPTH +! QTY_DISSOLVED_INORGANIC_SIO3 +! QTY_MESOZOOPLANKTON_CARBON +! QTY_MICROZOOPLANKTON_CARBON +! QTY_BGC_PARAM ! ! END DART PREPROCESS QUANTITY DEFINITIONS diff --git a/assimilation_code/modules/observations/ocean_quantities_mod.f90 b/assimilation_code/modules/observations/ocean_quantities_mod.f90 index 5abc85201e..26e04124fb 100644 --- a/assimilation_code/modules/observations/ocean_quantities_mod.f90 +++ b/assimilation_code/modules/observations/ocean_quantities_mod.f90 @@ -42,43 +42,7 @@ ! QTY_DISSOLVED_INORGANIC_SIO3 ! QTY_MESOZOOPLANKTON_CARBON ! QTY_MICROZOOPLANKTON_CARBON -! QTY_PARAM_AUTOTROPH1_KCO2 -! QTY_PARAM_AUTOTROPH1_KDOP -! QTY_PARAM_AUTOTROPH1_KFE -! QTY_PARAM_AUTOTROPH1_KNH4 -! QTY_PARAM_AUTOTROPH1_KNO3 -! QTY_PARAM_AUTOTROPH1_KPO4 -! QTY_PARAM_AUTOTROPH1_KSIO3 -! QTY_PARAM_AUTOTROPH1_ALPHAPI -! QTY_PARAM_AUTOTROPH1_PCREF -! QTY_PARAM_AUTOTROPH2_KCO2 -! QTY_PARAM_AUTOTROPH2_KDOP -! QTY_PARAM_AUTOTROPH2_KFE -! QTY_PARAM_AUTOTROPH2_KNH4 -! QTY_PARAM_AUTOTROPH2_KNO3 -! QTY_PARAM_AUTOTROPH2_KPO4 -! QTY_PARAM_AUTOTROPH2_KSIO3 -! QTY_PARAM_AUTOTROPH2_ALPHAPI -! QTY_PARAM_AUTOTROPH2_PCREF -! QTY_PARAM_AUTOTROPH3_KCO2 -! QTY_PARAM_AUTOTROPH3_KDOP -! QTY_PARAM_AUTOTROPH3_KFE -! QTY_PARAM_AUTOTROPH3_KNH4 -! QTY_PARAM_AUTOTROPH3_KNO3 -! QTY_PARAM_AUTOTROPH3_KPO4 -! QTY_PARAM_AUTOTROPH3_KSIO3 -! QTY_PARAM_AUTOTROPH3_ALPHAPI -! QTY_PARAM_AUTOTROPH3_PCREF -! QTY_PARAM_AUTOTROPH4_KCO2 -! QTY_PARAM_AUTOTROPH4_KDOP -! QTY_PARAM_AUTOTROPH4_KFE -! QTY_PARAM_AUTOTROPH4_KNH4 -! QTY_PARAM_AUTOTROPH4_KNO3 -! QTY_PARAM_AUTOTROPH4_KPO4 -! QTY_PARAM_AUTOTROPH4_KSIO3 -! QTY_PARAM_AUTOTROPH4_ALPHAPI -! QTY_PARAM_AUTOTROPH4_PCREF -! QTY_PARAM_GRAZING11_ZUMAX0 +! QTY_BGC_PARAM ! ! ! fixme - these units are hardcoded in obs_diag and shouldn't be ! QTY_U_WIND_COMPONENT diff --git a/models/MARBL_column/model_mod.f90 b/models/MARBL_column/model_mod.f90 index b90543202e..aa4c845ec7 100644 --- a/models/MARBL_column/model_mod.f90 +++ b/models/MARBL_column/model_mod.f90 @@ -136,9 +136,6 @@ subroutine static_init_model() module_initialized = .true. -! Print module information to log file and stdout. -call register_module(source) - ! Read values from the namelist call find_namelist_in_file("input.nml", "model_nml", iunit) @@ -253,10 +250,6 @@ end function get_model_size ! the values in expected_obs. The istatus variables should be returned as ! 0 unless there is some problem in computing the interpolation in ! which case a positive istatus should be returned. -! -! For applications in which only perfect model experiments -! with identity observations (i.e. only the value of a particular -! state variable is observed), this can be a NULL INTERFACE. subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus) @@ -283,8 +276,6 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs loc_temp = get_location(location) requested_depth = loc_temp(3) -! print *, "REQUESTED DEPTH = ",requested_depth - ! extracting the current layer thicknesses for each ensemble member. thickness_id = get_varid_from_kind(state_dom_id, QTY_LAYER_THICKNESS) @@ -295,12 +286,13 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs layer_thicknesses(layer_index, :) = get_state(thickness_index, state_handle) end do + ! performing the interpolation for each ensemble member individually. do ens_index = 1, ens_size - ! print *, "BASIN DEPTH = ",-basin_depth(1,1) - ! print *, "----------------------------------------------------" - ! print *, "computing centers of layers" - ! print *, "----------------------------------------------------" + !print *, "BASIN DEPTH = ",-basin_depth(1,1) + !print *, "----------------------------------------------------" + !print *, "computing centers of layers" + !print *, "----------------------------------------------------" ! locating the layer index to be used as the upper interpolation point for this ensemble member. layer_index = nz @@ -310,7 +302,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs layerdepth_top = layerdepth_bottom & ! depth at top of the layer given by layer_index. + layer_thicknesses(layer_index, ens_index) - ! print *, "layer = ",layer_index,", center = ",layerdepth_center,", bottom = ",layerdepth_bottom,", top = ",layerdepth_top + !print *, "layer = ",layer_index,", center = ",layerdepth_center,", bottom = ",layerdepth_bottom,", top = ",layerdepth_top do while((layerdepth_center < requested_depth) .and. (layer_index > 1)) layer_index = layer_index - 1 @@ -318,7 +310,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs layerdepth_center = layerdepth_bottom + 0.5 * layer_thicknesses(layer_index, ens_index) layerdepth_top = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) - ! print *, "layer = ",layer_index,", bottom = ",layerdepth_bottom,", center = ",layerdepth_center,", top = ",layerdepth_top + !print *, "layer = ",layer_index,", bottom = ",layerdepth_bottom,", center = ",layerdepth_center,", top = ",layerdepth_top end do @@ -326,9 +318,9 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs if((requested_depth < -basin_depth(1,1)) .or. (layerdepth_top < requested_depth)) then ! case where the requested depth is below the ocean floor, or above the ocean surface - ! print *, "----------------------------------------------------" - ! print *, "depth is below ocean floor or above ocean surface" - ! print *, "----------------------------------------------------" + !print *, "----------------------------------------------------" + !print *, "depth is below ocean floor or above ocean surface" + !print *, "----------------------------------------------------" istatus(ens_index) = 1 expected_obs(ens_index) = MISSING_R8 @@ -338,9 +330,9 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! or the top half of the shallowest layer. In both cases, the "interpolated" value is ! simply the current value of that layer in MOM6. - ! print *, "----------------------------------------------------" - ! print *, "only using value from layer ",layer_index - ! print *, "----------------------------------------------------" + !print *, "----------------------------------------------------" + !print *, "only using value from layer ", layer_index + !print *, "----------------------------------------------------" istatus(ens_index) = 0 qty_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, qty_id) @@ -354,8 +346,8 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! the center of another. We interpolate linearly between the nearest layers above ! and below. - ! print *, "----------------------------------------------------" - ! print *, "interpolating between layers ",layer_index," and ",(layer_index + 1) + !print *, "----------------------------------------------------" + !print *, "interpolating between layers ", layer_index, " and ", (layer_index + 1) istatus(ens_index) = 0 @@ -363,23 +355,23 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs depth_above = layerdepth_center depth_below = layerdepth_top - layer_thicknesses(layer_index, ens_index) & - .5*layer_thicknesses(layer_index + 1, ens_index) - + ! extracting the quantity values at the layers above and below - qty_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, qty_id) + qty_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, qty_id) state_slice = get_state(qty_index, state_handle) - val_above = state_slice(ens_index) + val_above = state_slice(ens_index) - qty_index = get_dart_vector_index(1, 1, layer_index + 1, state_dom_id, qty_id) + qty_index = get_dart_vector_index(1, 1, layer_index + 1, state_dom_id, qty_id) state_slice = get_state(qty_index, state_handle) - val_below = state_slice(ens_index) + val_below = state_slice(ens_index) - ! print *, "corresponding to the values: ",val_above," and ",val_below - ! print *, "----------------------------------------------------" + !print *, "corresponding to the values: ", val_above, " and ", val_below + !print *, "----------------------------------------------------" ! linear interpolation expected_obs(ens_index) = val_above + (requested_depth - depth_above) * (val_below - val_above) / (depth_below - depth_above) - ! print *, "final value = ",expected_obs(ens_index) + !print *, "final value = ",expected_obs(ens_index) end if end do @@ -634,6 +626,15 @@ subroutine read_ocean_geometry() end subroutine read_ocean_geometry +!------------------------------------------------------------------ +! Does any shutdown and clean-up needed for model. Can be a NULL +! INTERFACE if the model has no need to clean up storage, etc. + +subroutine end_model() + + +end subroutine end_model + !=================================================================== ! End of model_mod !=================================================================== diff --git a/models/MARBL_column/work/input.nml b/models/MARBL_column/work/input.nml index 16bd75f58f..1b12d11c8a 100644 --- a/models/MARBL_column/work/input.nml +++ b/models/MARBL_column/work/input.nml @@ -26,7 +26,7 @@ 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' estimate_params = .true. - model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_PARAM_AUTOTROPH1_KDOP ', '0.0', 'NA', 'UPDATE' + model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_BGC_PARAM', '0.0', 'NA', 'UPDATE' / 'params_input.txt', @@ -241,11 +241,11 @@ &model_mod_check_nml input_state_files = 'mom_in.nc', 'param_in.nc' output_state_files = 'mom_out.nc', 'param_out.nc' - test1thru = 3 + test1thru = 4 run_tests = 1 x_ind = 600 - loc_of_interest = 1.11, 0.54, -500.0 - quantity_of_interest = 'BATS_OXYGEN' + loc_of_interest = 296., 31., -500.0 + quantity_of_interest = 'QTY_DISSOLVED_OXYGEN' interp_test_dx = 0.02 interp_test_xrange = 0.0, 1.0 verbose = .true. From eb9d5373d7f5fd211dd182672ae1c8a7f6be198a Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 13:50:41 -0600 Subject: [PATCH 26/35] Passed all model-mod-check tests I went through all model-mod checks and made sure all tests are successful. The commit also includes some more cleaning for the model-mod and the input.nml --- models/MARBL_column/model_mod.f90 | 6 +----- models/MARBL_column/work/input.nml | 14 +++++++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/models/MARBL_column/model_mod.f90 b/models/MARBL_column/model_mod.f90 index aa4c845ec7..86b51ddd2a 100644 --- a/models/MARBL_column/model_mod.f90 +++ b/models/MARBL_column/model_mod.f90 @@ -492,7 +492,7 @@ subroutine nc_write_model_atts(ncid, domain_id) call nc_add_global_creation_time(ncid) call nc_add_global_attribute(ncid, "model_source", source ) -call nc_add_global_attribute(ncid, "model", "template") +call nc_add_global_attribute(ncid, "model", "MARBL_column") call nc_end_define_mode(ncid) @@ -608,8 +608,6 @@ subroutine read_num_layers() end subroutine read_num_layers !------------------------------------------------------------ -! ocean_geom are 2D state sized static data -! HK Do these arrays become too big in high res cases? subroutine read_ocean_geometry() integer :: ncid @@ -627,8 +625,6 @@ subroutine read_ocean_geometry() end subroutine read_ocean_geometry !------------------------------------------------------------------ -! Does any shutdown and clean-up needed for model. Can be a NULL -! INTERFACE if the model has no need to clean up storage, etc. subroutine end_model() diff --git a/models/MARBL_column/work/input.nml b/models/MARBL_column/work/input.nml index 1b12d11c8a..2ed7e0d4da 100644 --- a/models/MARBL_column/work/input.nml +++ b/models/MARBL_column/work/input.nml @@ -241,13 +241,17 @@ &model_mod_check_nml input_state_files = 'mom_in.nc', 'param_in.nc' output_state_files = 'mom_out.nc', 'param_out.nc' - test1thru = 4 + test1thru = 7 run_tests = 1 x_ind = 600 loc_of_interest = 296., 31., -500.0 quantity_of_interest = 'QTY_DISSOLVED_OXYGEN' - interp_test_dx = 0.02 - interp_test_xrange = 0.0, 1.0 - verbose = .true. + interp_test_vertcoord = 'VERTISHEIGHT' + interp_test_lonrange = 295., 297. + interp_test_dlon = 0.10 + interp_test_latrange = 30., 32. + interp_test_dlat = 0.10 + interp_test_vertrange = 0.0, -100.00 + interp_test_dvert = -10.0 + verbose = .true. / - From 44d3386fe064eecb926988bcde7ad73c62e94a42 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 16:42:04 -0600 Subject: [PATCH 27/35] Modifications to the obs_converter Updated the BATS station location in the obs_converter. Previously it assumed a lon of 64 while it should be 64W or 296. Also, the BATS text data file has been modified and that required changing the input parameters for reading the quantities properly. filter has been run several times and obs_seq.final was assessed with no apparent issues. --- models/MARBL_column/work/input.nml | 3 --- .../obs_converters/BATS/bats_to_obs.f90 | 4 +++- .../obs_converters/BATS/work/input.nml | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/models/MARBL_column/work/input.nml b/models/MARBL_column/work/input.nml index 2ed7e0d4da..d76881e769 100644 --- a/models/MARBL_column/work/input.nml +++ b/models/MARBL_column/work/input.nml @@ -29,9 +29,6 @@ model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_BGC_PARAM', '0.0', 'NA', 'UPDATE' / -'params_input.txt', -'params_output.txt', - &filter_nml single_file_in = .false., input_state_files = '', diff --git a/observations/obs_converters/BATS/bats_to_obs.f90 b/observations/obs_converters/BATS/bats_to_obs.f90 index d960104fb4..083225c65d 100644 --- a/observations/obs_converters/BATS/bats_to_obs.f90 +++ b/observations/obs_converters/BATS/bats_to_obs.f90 @@ -39,6 +39,8 @@ program bats_to_obs BATS_PHOSPHATE, BATS_SILICATE/) real(r8), parameter :: MIN_OBS_ERROR = 0.1_r8 +real(r8), parameter :: bats_lon = 360.0_r8 - 64.0_r8 +real(r8), parameter :: bats_lat = 31.0_r8 ! namelist variables, changeable at runtime character(len=256) :: text_input_file, obs_out_dir @@ -278,7 +280,7 @@ program bats_to_obs obs_err = max(obs_uncertainties(otype_index)*ovalue, MIN_OBS_ERROR) - call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + call create_3d_obs(bats_lat, bats_lon, vert, VERTISHEIGHT, & ovalue, OTYPE_ORDERING(otype_index), obs_err, & oday, osec, qc, obs) diff --git a/observations/obs_converters/BATS/work/input.nml b/observations/obs_converters/BATS/work/input.nml index 6a20cd5e8e..ec2a90d59e 100644 --- a/observations/obs_converters/BATS/work/input.nml +++ b/observations/obs_converters/BATS/work/input.nml @@ -1,19 +1,19 @@ &bats_to_obs_nml - text_input_file = "../data/bats_bottle.txt" + text_input_file = "../bats_bottle.txt" max_lines = 68000 ! upper bound on the number of lines in the file that record observations read_starting_at_line = 61 date_firstcol = 14 ! first column of the YYYYMMDD date code at each line hourminute_firstcol = 35 ! first column of the HHMM time stamp at each line lat_cols = 42, 47 ! first and last columns where latitude, longitude, and vertical are recorded lon_cols = 51, 56 - vert_cols = 58, 63 - scalar_obs_cols = 102, 107, ! i^th row of this table should list the first and last - 126, 131, ! columns where the value of the i^th observation variable - 134, 139, ! is recorded. Ordering of observation variables is defined - 141, 147, ! by the OTYPE_ORDERING parameter in bats_to_obs.f90. - 158, 164, - 166, 172 + vert_cols = 64, 69 + scalar_obs_cols = 113, 119, ! i^th row of this table should list the first and last + 137, 143, ! columns where the value of the i^th observation variable + 145, 151, ! is recorded. Ordering of observation variables is defined + 153, 159, ! by the OTYPE_ORDERING parameter in bats_to_obs.f90. + 170, 176, + 178, 184 obs_uncertainties = 0.2, ! i^th entry of this list gives the uncertainty associated 0.2, ! with the i^th observation variable. Ordering of observation 0.2, ! variables is defined by the OTYPE_ORDERING parameter in @@ -30,7 +30,8 @@ input_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' output_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/obs_kind_mod.f90' obs_type_files = '../../../../observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '../../../../assimilation_code/modules/observations/default_quantities_mod.f90', '../../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' + quantity_files = '../../../../assimilation_code/modules/observations/default_quantities_mod.f90', + '../../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' / &obs_kind_nml From 495b6dbc4cf1ed1576a331933a819ff19d1279e2 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 22:13:09 -0600 Subject: [PATCH 28/35] Added model documentation Added information in the readme.rst file --- models/MARBL_column/readme.rst | 131 ++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/models/MARBL_column/readme.rst b/models/MARBL_column/readme.rst index 9119443802..135bdb65e6 100644 --- a/models/MARBL_column/readme.rst +++ b/models/MARBL_column/readme.rst @@ -1,5 +1,128 @@ -MARBL_joint_estimation -======================= +MARBL_column +============ -.. attention:: - Add your model documentation here. +**MARBL** stands for the Marine Biogeochemistry Library; it's a modular biogeochemical modeling suite for next-generatioon models. +It simulates marine ecosystem dynamics and the coupled cycles of carbon, nitrogen, phosphorus, iron, silicon, and oxygen. +It is a component of the Community Earth System Model (`CESM `_) and is often coupled to other physical ocean models such as +the Modular Ocean Model (`MOM6 `_). + +For a detailed description of the model, the reader is refered to Long et al., 2021 [1]_. + +The MARBL source code can be downloaded from https://github.com/marbl-ecosys/MARBL. You may also want to read +MARBL's documentation `here `_. + +This MARBL-DART interface was developed by `Robin Armstrong `_. Thanks Robin! + +Overview +-------- +**MARBL_column** provides an interface between DART and a 1D (column) configuration of MARBL. +It's designed to be used at locations where in-situ data is abundant such as +`Bermuda Atlantic Time-series Study (BATS) station `_, +`Weather Station Mike `_, +`Hawaii Ocean Time-series (HOT) `_ ... to name a few. + +The code is designed to perform 3 kinds of data assimilation (DA) experiments: + +#. **State Estimation:** where the prognostic state variables of MARBL such as nitrate concerntration are updated. + To achive this, you'll need to set + ``estimate_params = .false.`` within ``&model_nml`` in the namelist file ``input.nml`` + +#. **State and Parameters Estimation:** where both the state and a set of model parameters are updated. + MARBL has a long list of uncertain model parameters that can be constrained alongside the state. + This usually improves the prediction skill of the model and alleviate some of its biases. + To achieve this DA exercise, you'll need to set + ``estimate_params = .true.`` + +#. **Parameters Estimation only:** where only the parameters are constrained using the data. DART + will still need to read in the state to construct ensemble covariances and compute innovations. + The only difference is that the ensemble increments are only regressed onto the unknown parameters. + To achive this goal, you'll need to set ``estimate_params = .true.`` and turn the update status for + all state variable to + ``NO_COPY_BACK`` + This ensures that the state will not be updated. The ``NO_COPY_BACK`` option is added as the 5th entry + in the state table (after the variable name, its associated quantity and its physical bounds) within ``&model_nml`` + +Namelist +-------- +The ``&model_nml`` variables and their default values are listed here: + +.. code-block:: fortran + + &model_nml + template_file = 'member_0001/RESTART/MOM.res.nc', 'member_0001/marbl_params.nc', + ocean_geometry = 'member_0001/ocean_geometry.nc', + station_location = -64, 31 + time_step_days = 1, + time_step_seconds = 0, + model_state_variables = 'NO3 ', 'QTY_NITRATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'SiO3 ', 'QTY_DISSOLVED_INORGANIC_SIO3 ', '0.0', 'NA', 'UPDATE ', + 'PO4 ', 'QTY_PHOSPHATE_CONCENTRATION ', '0.0', 'NA', 'UPDATE ', + 'Fe ', 'QTY_DISSOLVED_INORGANIC_IRON ', '0.0', 'NA', 'UPDATE ', + 'DIC ', 'QTY_DISSOLVED_INORGANIC_CARBON', '0.0', 'NA', 'UPDATE ', + 'O2 ', 'QTY_DISSOLVED_OXYGEN ', '0.0', 'NA', 'UPDATE ', + 'DOC ', 'QTY_DISSOLVED_ORGANIC_CARBON ', '0.0', 'NA', 'UPDATE ', + 'DON ', 'QTY_DISSOLVED_ORGANIC_NITROGEN', '0.0', 'NA', 'UPDATE ', + 'DOP ', 'QTY_DISSOLVED_ORGANIC_P ', '0.0', 'NA', 'UPDATE ', + 'ALK ', 'QTY_ALKALINITY ', '0.0', 'NA', 'UPDATE ', + 'microzooC', 'QTY_MICROZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'mesozooC ', 'QTY_MESOZOOPLANKTON_CARBON ', '0.0', 'NA', 'UPDATE ', + 'h ', 'QTY_LAYER_THICKNESS ', '0.0', 'NA', 'NO_COPY_BACK' + estimate_params = .true. + model_parameters = 'autotroph_settings(1)%kDOP ', 'QTY_BGC_PARAM', '0.0', 'NA', 'UPDATE' + / + +This namelist provides control over the kind of DA experiment as described abvove. + ++-------------------------------------+--------------------+------------------------------------------------------------+ +| Item | Type | Description | ++=====================================+====================+============================================================+ +| ``template_file`` | character(len=256) | MARBL restart file including MARBL's prognostic variables | +| | | and other grid information such as the ocean layers. | +| | | The state variables read from this file are listed in | +| | | in the ``model_state_variables`` | +| | | | +| | | There is another template file corresponding to the | +| | | BGC parameters that we intend to estimate. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``ocean_geometry`` | character(len=256) | The ocean geometry file is used read the ``basin_depth`` | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``station_location`` | real(2) | Longitude and latitude of the ocean column location. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``time_step_days`` | integer | The number of days to advance the model for each | +| | | assimilation. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``time_step_seconds`` | integer | In addition to ``time_step_days``, the number | +| | | of seconds to advance the model for each assimilation. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``model_state_variables`` | character(:,5) | Strings that associate MARBL variables with a DART | +| | | quantity. They also describe their physical bounds and | +| | | whether or not to write the updated values to the restart | +| | | files. These variables will be read from the MARBL restart | +| | | file and modified by the assimilation. Some (perhaps all) | +| | | will be used by the forward observation operators. If the | +| | | 5th column is ``UPDATE``, the output files will have the | +| | | modified (assimilated,posterior) values. If the 5th | +| | | column is ``NO_COPY_BACK``, that variable will not be | +| | | written to the restart files. **The DART diagnostic files | +| | | will always have the (modified) posterior values.** | +| | | Diagnostic variables that are useful for the calculation | +| | | of the forward observation operator but have no impact on | +| | | the forecast trajectory of the model could have a value of | +| | | ``NO_COPY_BACK``. The 3rd and 4th column list the minimum | +| | | and maximum allowed values for the updated variables. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``estimate_params`` | logical | A switch to turn on/off parameter estimation. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``model_parameters`` | character(:,5) | Similar to ``model_state_variables``, this is a list of | +| | | parameters that will take part in the DART state and | +| | | would possibly get updated. | ++-------------------------------------+--------------------+------------------------------------------------------------+ + + +References +---------- + +.. [1] Long, Matthew C., J. Keith Moore, Keith Lindsay, Michael Levy, Scott C. Doney, + Jessica Y. Luo, Kristen M. Krumhardt, Robert T. Letscher, Maxwell Grover, and Zephyr T. Sylvester. + "Simulations with the marine biogeochemistry library (MARBL)." + Journal of Advances in Modeling Earth Systems 13, no. 12 (2021): e2021MS002647. From 0a2081f72cb09eacab058b6e8d60852d91bcf64f Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 28 Aug 2024 22:55:37 -0600 Subject: [PATCH 29/35] Documentation of the obs_converter Removed the old readme.md file and added a new rst readme file describing the converter and its namelist options. --- observations/obs_converters/BATS/README.md | 2 - observations/obs_converters/BATS/readme.rst | 94 +++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) delete mode 100644 observations/obs_converters/BATS/README.md create mode 100644 observations/obs_converters/BATS/readme.rst diff --git a/observations/obs_converters/BATS/README.md b/observations/obs_converters/BATS/README.md deleted file mode 100644 index 658f4cecd3..0000000000 --- a/observations/obs_converters/BATS/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This folder contains files adapted from those in DART/observations/obs\_converters/text, for the purpose of converting data from the [Bermude Atlantic Time-Series Study](https://bats.bios.asu.edu/) (BATS) into a format readable by DART. - diff --git a/observations/obs_converters/BATS/readme.rst b/observations/obs_converters/BATS/readme.rst new file mode 100644 index 0000000000..e32958d929 --- /dev/null +++ b/observations/obs_converters/BATS/readme.rst @@ -0,0 +1,94 @@ +BATS +==== + +Overview: +--------- +BATS stands for the `Bermuda Atlantic Time-series Study `_. +BATS has collected data on the physical, biological, and chemical properties of +the ocean every month since 1988. BATS was established to uncover mysteries of the +deep by analyzing important hydrographic and biological parameters throughout +the water column. + +Data Source: +------------ +Water column data from BATS (roughly 31N, 64W) can be downloaded from https://bats.bios.asu.edu/bats-data/ +The data can be obtained in different forms. This converter operates on the ASCII formatted file, +often named ``bats_bottle.txt`` + +The data is huge extending from Oct 1988 to present day. It also consists of a long list of information +such as + Depth, Oxygen, CO2, Nitrate, Phosphate, Silicate, Alkalinity, Organic Carbon, Bacteria, ... + +Observation Converter: +---------------------- +The obs converter is a program called ``bats_to_obs`` and has a namelist by the name ``&bats_to_obs_nml`` +Namelists start with an ampersand '&' and terminate with a slash '/'. + + .. code-block:: fortran + + &bats_to_obs_nml + text_input_file = "../bats_bottle.txt" + max_lines = 68000 + read_starting_at_line = 61 + date_firstcol = 14 + hourminute_firstcol = 35 + lat_cols = 42, 47 + lon_cols = 51, 56 + vert_cols = 64, 69 + scalar_obs_cols = 113, 119, + 137, 143, + 145, 151, + 153, 159, + 170, 176, + 178, 184 + obs_uncertainties = 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + obs_out_dir = '../obs_seq_files', + debug = .true. + / + +This namelist provides control over the kind of observations to extract from the file in addition to their uncertainties. +In its current form, the observations that are extracted from the data file are: + ``BATS_OXYGEN``, ``BATS_INORGANIC_CARBON``, ``BATS_ALKALINITY``, ``BATS_NITRATE``, ``BATS_PHOSPHATE``, ``BATS_SILICATE`` + ++-------------------------------------+--------------------+------------------------------------------------------------+ +| Contents | Type | Description | ++=====================================+====================+============================================================+ +| ``text_input_file`` | character(len=256) | Pathname to the data file: ``bats_bottle.txt`` | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``max_lines`` | integer | Upper bound on the number of lines in the file that record | +| | | observations. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``read_starting_at_line`` | integer | Skip the information in the header of the file. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``date_firstcol`` | integer | First column of the YYYYMMDD date code at each line. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``hourminute_firstcol`` | integer | First column of the HHMM time stamp at each line. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``lat_cols`` | integer(2) | First and last columns where latitude is recorded. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``lon_cols`` | integer(2) | First and last columns where longitude is recorded. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``vert_cols`` | integer(2) | First and last columns where depth is recorded. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``scalar_obs_cols `` | integer(2, :) | i^th row of this table should list the first and last | +| | | columns where the value of the i^th observation variable | +| | | is recorded. Ordering of observation variables is defined | +| | | by the OTYPE_ORDERING parameter in bats_to_obs.f90. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``obs_uncertainties`` | real(2, :) | i^th entry of this list gives the uncertainty associated | +| | | with the i^th observation variable. | +| | | | +| | | The observation error variance is defind as the square of | +| | | the product of the ``obs_uncertainties`` and the | +| | | observation value. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``obs_out_dir`` | character(len=256) | Pathname to obs_seq files resulting from the converter. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``debug`` | logical | A switch that makes the converetr prints useful | +| | | information as it runs. | ++-------------------------------------+--------------------+------------------------------------------------------------+ From 478c9b65ea83a1a254ffa307e68f59553f867c6e Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Thu, 29 Aug 2024 11:17:36 -0600 Subject: [PATCH 30/35] Consolidated converter + improved documentation Added the scripts and code to generate climatology data to the BATS converter. This includes a python script and fortran code. The namelists were also consolidated. The BATS_clim converter has been removed. Documentation of both the model and the converter was also modified for clarity. --- models/MARBL_column/readme.rst | 21 ++++--- .../{BATS_clim => BATS}/bats_climatology.py | 0 .../{BATS_clim => BATS}/bats_to_clim_obs.f90 | 4 +- observations/obs_converters/BATS/readme.rst | 55 ++++++++++++------- .../obs_converters/BATS/work/input.nml | 8 +++ .../obs_converters/BATS/work/quickbuild.sh | 2 +- .../obs_converters/BATS_clim/README.md | 2 - .../obs_converters/BATS_clim/work/input.nml | 50 ----------------- .../BATS_clim/work/quickbuild.sh | 40 -------------- 9 files changed, 58 insertions(+), 124 deletions(-) rename observations/obs_converters/{BATS_clim => BATS}/bats_climatology.py (100%) rename observations/obs_converters/{BATS_clim => BATS}/bats_to_clim_obs.f90 (98%) delete mode 100644 observations/obs_converters/BATS_clim/README.md delete mode 100644 observations/obs_converters/BATS_clim/work/input.nml delete mode 100755 observations/obs_converters/BATS_clim/work/quickbuild.sh diff --git a/models/MARBL_column/readme.rst b/models/MARBL_column/readme.rst index 135bdb65e6..406fc9d068 100644 --- a/models/MARBL_column/readme.rst +++ b/models/MARBL_column/readme.rst @@ -3,8 +3,8 @@ MARBL_column **MARBL** stands for the Marine Biogeochemistry Library; it's a modular biogeochemical modeling suite for next-generatioon models. It simulates marine ecosystem dynamics and the coupled cycles of carbon, nitrogen, phosphorus, iron, silicon, and oxygen. -It is a component of the Community Earth System Model (`CESM `_) and is often coupled to other physical ocean models such as -the Modular Ocean Model (`MOM6 `_). +It is a component of the Community Earth System Model (`CESM `_) and is often coupled to +other physical ocean models such as the Modular Ocean Model (`MOM6 `_). For a detailed description of the model, the reader is refered to Long et al., 2021 [1]_. @@ -25,20 +25,24 @@ The code is designed to perform 3 kinds of data assimilation (DA) experiments: #. **State Estimation:** where the prognostic state variables of MARBL such as nitrate concerntration are updated. To achive this, you'll need to set - ``estimate_params = .false.`` within ``&model_nml`` in the namelist file ``input.nml`` + ``estimate_params = .false.`` within ``&model_nml`` in the namelist file ``input.nml`` #. **State and Parameters Estimation:** where both the state and a set of model parameters are updated. MARBL has a long list of uncertain model parameters that can be constrained alongside the state. - This usually improves the prediction skill of the model and alleviate some of its biases. + This usually improves the prediction skill of the model and alleviates some of its biases. To achieve this DA exercise, you'll need to set - ``estimate_params = .true.`` - + ``estimate_params = .true.`` + + The combined DART state will be of the form :math:`Z_k = \left[ \mathbf{x}_k, \boldsymbol{\theta} \right]^T` + where :math:`Z_k` is the joint state, :math:`\mathbf{x}` and parameters, :math:`\boldsymbol{\theta}` + vector at time ``t_k`` + #. **Parameters Estimation only:** where only the parameters are constrained using the data. DART will still need to read in the state to construct ensemble covariances and compute innovations. The only difference is that the ensemble increments are only regressed onto the unknown parameters. To achive this goal, you'll need to set ``estimate_params = .true.`` and turn the update status for all state variable to - ``NO_COPY_BACK`` + ``NO_COPY_BACK`` This ensures that the state will not be updated. The ``NO_COPY_BACK`` option is added as the 5th entry in the state table (after the variable name, its associated quantity and its physical bounds) within ``&model_nml`` @@ -84,7 +88,7 @@ This namelist provides control over the kind of DA experiment as described abvov | | | There is another template file corresponding to the | | | | BGC parameters that we intend to estimate. | +-------------------------------------+--------------------+------------------------------------------------------------+ -| ``ocean_geometry`` | character(len=256) | The ocean geometry file is used read the ``basin_depth`` | +| ``ocean_geometry`` | character(len=256) | The ocean geometry file is used to read ``basin_depth`` | +-------------------------------------+--------------------+------------------------------------------------------------+ | ``station_location`` | real(2) | Longitude and latitude of the ocean column location. | +-------------------------------------+--------------------+------------------------------------------------------------+ @@ -121,7 +125,6 @@ This namelist provides control over the kind of DA experiment as described abvov References ---------- - .. [1] Long, Matthew C., J. Keith Moore, Keith Lindsay, Michael Levy, Scott C. Doney, Jessica Y. Luo, Kristen M. Krumhardt, Robert T. Letscher, Maxwell Grover, and Zephyr T. Sylvester. "Simulations with the marine biogeochemistry library (MARBL)." diff --git a/observations/obs_converters/BATS_clim/bats_climatology.py b/observations/obs_converters/BATS/bats_climatology.py similarity index 100% rename from observations/obs_converters/BATS_clim/bats_climatology.py rename to observations/obs_converters/BATS/bats_climatology.py diff --git a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 b/observations/obs_converters/BATS/bats_to_clim_obs.f90 similarity index 98% rename from observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 rename to observations/obs_converters/BATS/bats_to_clim_obs.f90 index 7dcd511f14..c9db561c89 100644 --- a/observations/obs_converters/BATS_clim/bats_to_clim_obs.f90 +++ b/observations/obs_converters/BATS/bats_to_clim_obs.f90 @@ -40,6 +40,8 @@ program bats_to_clim_obs BATS_PHOSPHATE, BATS_SILICATE/) real(r8), parameter :: MIN_OBS_ERROR = 0.1_r8 +real(r8), parameter :: bats_lon = 360.0_r8 - 64.0_r8 +real(r8), parameter :: bats_lat = 31.0_r8 ! namelist variables, changeable at runtime character(len=256) :: text_input_file, obs_out_dir @@ -227,7 +229,7 @@ program bats_to_clim_obs end if ! adding the observation - call create_3d_obs(31.0_r8, 64.0_r8, vert, VERTISHEIGHT, & + call create_3d_obs(bats_lat, bats_lon, vert, VERTISHEIGHT, & ovalue, OTYPE_ORDERING(otype_index), obs_err, & oday, osec, qc, obs) diff --git a/observations/obs_converters/BATS/readme.rst b/observations/obs_converters/BATS/readme.rst index e32958d929..97a2a0f99c 100644 --- a/observations/obs_converters/BATS/readme.rst +++ b/observations/obs_converters/BATS/readme.rst @@ -6,16 +6,16 @@ Overview: BATS stands for the `Bermuda Atlantic Time-series Study `_. BATS has collected data on the physical, biological, and chemical properties of the ocean every month since 1988. BATS was established to uncover mysteries of the -deep by analyzing important hydrographic and biological parameters throughout -the water column. +deep ocean by analyzing important hydrographic and biological parameters +throughout the water column. Data Source: ------------ Water column data from BATS (roughly 31N, 64W) can be downloaded from https://bats.bios.asu.edu/bats-data/ -The data can be obtained in different forms. This converter operates on the ASCII formatted file, +The data is stored in in different forms. This converter operates on the ASCII formatted file, often named ``bats_bottle.txt`` -The data is huge extending from Oct 1988 to present day. It also consists of a long list of information +The data is huge extending from Oct 1988 to present day. It consists of a long list of information such as Depth, Oxygen, CO2, Nitrate, Phosphate, Silicate, Alkalinity, Organic Carbon, Bacteria, ... @@ -28,24 +28,24 @@ Namelists start with an ampersand '&' and terminate with a slash '/'. &bats_to_obs_nml text_input_file = "../bats_bottle.txt" - max_lines = 68000 + max_lines = 68000 read_starting_at_line = 61 - date_firstcol = 14 - hourminute_firstcol = 35 - lat_cols = 42, 47 + date_firstcol = 14 + hourminute_firstcol = 35 + lat_cols = 42, 47 lon_cols = 51, 56 vert_cols = 64, 69 - scalar_obs_cols = 113, 119, - 137, 143, - 145, 151, - 153, 159, + scalar_obs_cols = 113, 119, + 137, 143, + 145, 151, + 153, 159, 170, 176, 178, 184 - obs_uncertainties = 0.2, - 0.2, - 0.2, - 0.2, - 0.2, + obs_uncertainties = 0.2, + 0.2, + 0.2, + 0.2, + 0.2, 0.2 obs_out_dir = '../obs_seq_files', debug = .true. @@ -75,13 +75,13 @@ In its current form, the observations that are extracted from the data file are: +-------------------------------------+--------------------+------------------------------------------------------------+ | ``vert_cols`` | integer(2) | First and last columns where depth is recorded. | +-------------------------------------+--------------------+------------------------------------------------------------+ -| ``scalar_obs_cols `` | integer(2, :) | i^th row of this table should list the first and last | -| | | columns where the value of the i^th observation variable | +| ``scalar_obs_cols `` | integer(:, 2) | ith row of this table should list the first and last | +| | | columns where the value of the ith observation variable | | | | is recorded. Ordering of observation variables is defined | | | | by the OTYPE_ORDERING parameter in bats_to_obs.f90. | +-------------------------------------+--------------------+------------------------------------------------------------+ -| ``obs_uncertainties`` | real(2, :) | i^th entry of this list gives the uncertainty associated | -| | | with the i^th observation variable. | +| ``obs_uncertainties`` | real(:) | ith entry of this list gives the uncertainty associated | +| | | with the ith observation variable. | | | | | | | | The observation error variance is defind as the square of | | | | the product of the ``obs_uncertainties`` and the | @@ -92,3 +92,16 @@ In its current form, the observations that are extracted from the data file are: | ``debug`` | logical | A switch that makes the converetr prints useful | | | | information as it runs. | +-------------------------------------+--------------------+------------------------------------------------------------+ + +Climatology: +~~~~~~~~~~~ +On top of assimilating real-time data, we often observe the quasi-cyclostationary behavior of the biogeochemical system +over the period of one year, and we update MARBL parameters by comparing this observed climatology to a climatology +predicted by MARBL. This usually involves running different forms of the ensmeble smoother where the model is re-run +using the updated parameters over long periods of times. + +To access the observed climatology at BATS, the script ``bats_climatology.py`` can be used to generate the climatology +by averaging the data over time. The program ``bats_to_clim_obs`` can then be executed to generate DART-style +observation sequence files using the climatological data. This code also supports +`Multiple Data Assimilation (MDA) `_ in +which the observations are assimilated multiple times with inflated observation error variance. diff --git a/observations/obs_converters/BATS/work/input.nml b/observations/obs_converters/BATS/work/input.nml index ec2a90d59e..bcca4c032d 100644 --- a/observations/obs_converters/BATS/work/input.nml +++ b/observations/obs_converters/BATS/work/input.nml @@ -24,6 +24,14 @@ debug = .true. / +&bats_to_clim_obs_nml + text_input_file = "../data/bats_climatology.txt" + max_lines = 3000 + obs_err_var_inflation = 10 + obs_out_dir = '../obs_seq_files', + debug = .true. + / + &preprocess_nml input_obs_def_mod_file = '../../../../observations/forward_operators/DEFAULT_obs_def_mod.F90' output_obs_def_mod_file = '../../../../observations/forward_operators/obs_def_mod.f90' diff --git a/observations/obs_converters/BATS/work/quickbuild.sh b/observations/obs_converters/BATS/work/quickbuild.sh index de837d121f..ba99a14b5b 100755 --- a/observations/obs_converters/BATS/work/quickbuild.sh +++ b/observations/obs_converters/BATS/work/quickbuild.sh @@ -12,9 +12,9 @@ source "$DART"/build_templates/buildconvfunctions.sh CONVERTER=BATS LOCATION=threed_sphere - programs=( bats_to_obs +bats_to_clim_obs obs_sequence_tool advance_time ) diff --git a/observations/obs_converters/BATS_clim/README.md b/observations/obs_converters/BATS_clim/README.md deleted file mode 100644 index 658f4cecd3..0000000000 --- a/observations/obs_converters/BATS_clim/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This folder contains files adapted from those in DART/observations/obs\_converters/text, for the purpose of converting data from the [Bermude Atlantic Time-Series Study](https://bats.bios.asu.edu/) (BATS) into a format readable by DART. - diff --git a/observations/obs_converters/BATS_clim/work/input.nml b/observations/obs_converters/BATS_clim/work/input.nml deleted file mode 100644 index 9e558d88cb..0000000000 --- a/observations/obs_converters/BATS_clim/work/input.nml +++ /dev/null @@ -1,50 +0,0 @@ - -&bats_to_clim_obs_nml - text_input_file = "../data/bats_climatology.txt" - max_lines = 3000 - obs_err_var_inflation = 10 - obs_out_dir = '../obs_seq_files', - debug = .true. - / - -&preprocess_nml - input_obs_def_mod_file = '../../../../observations/forward_operators/DEFAULT_obs_def_mod.F90' - output_obs_def_mod_file = '../../../../observations/forward_operators/obs_def_mod.f90' - input_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90' - output_obs_qty_mod_file = '../../../../assimilation_code/modules/observations/obs_kind_mod.f90' - obs_type_files = '../../../../observations/forward_operators/obs_def_ocean_mod.f90' - quantity_files = '../../../../assimilation_code/modules/observations/default_quantities_mod.f90', '../../../../assimilation_code/modules/observations/ocean_quantities_mod.f90' - / - -&obs_kind_nml - assimilate_these_obs_types = 'BATS_OXYGEN', - 'BATS_INORGANIC_CARBON', - 'BATS_ALKALINITY', - 'BATS_NITRATE', - 'BATS_PHOSPHATE', - 'BATS_SILICATE' - / - -&location_nml - / - -&utilities_nml - module_details = .false. - / - -&obs_sequence_nml - write_binary_obs_sequence = .false. - / - -&obs_sequence_tool_nml - filename_seq = 'obs_seq.out' - filename_seq_list = '' - filename_out = 'obs_seq.copy' - print_only = .false. - gregorian_cal = .true. - first_obs_days = -1 - first_obs_seconds = -1 - last_obs_days = -1 - last_obs_seconds = -1 - / - diff --git a/observations/obs_converters/BATS_clim/work/quickbuild.sh b/observations/obs_converters/BATS_clim/work/quickbuild.sh deleted file mode 100755 index e0a572ae0a..0000000000 --- a/observations/obs_converters/BATS_clim/work/quickbuild.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -# DART software - Copyright UCAR. This open source software is provided -# by UCAR, "as is", without charge, subject to all terms of use at -# http://www.image.ucar.edu/DAReS/DART/DART_download - -main() { - -export DART=$(git rev-parse --show-toplevel) -source "$DART"/build_templates/buildconvfunctions.sh - -CONVERTER=BATS_clim -LOCATION=threed_sphere - - -programs=( -bats_to_clim_obs -obs_sequence_tool -advance_time -) - -# build arguments -arguments "$@" - -# clean the directory -\rm -f -- *.o *.mod Makefile .cppdefs - -# build and run preprocess before making any other DART executables -buildpreprocess - -# build -buildconv - - -# clean up -\rm -f -- *.o *.mod - -} - -main "$@" From 0cbb86053a970cf732da18973d1d79914d4bc4d0 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Thu, 29 Aug 2024 11:35:52 -0600 Subject: [PATCH 31/35] Deleted an obselete download script --- .../ocean_color/shell_scripts/submit_download.sh | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100755 observations/obs_converters/ocean_color/shell_scripts/submit_download.sh diff --git a/observations/obs_converters/ocean_color/shell_scripts/submit_download.sh b/observations/obs_converters/ocean_color/shell_scripts/submit_download.sh deleted file mode 100755 index cbda90d801..0000000000 --- a/observations/obs_converters/ocean_color/shell_scripts/submit_download.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -#PBS -N nasa_chlora_download -#PBS -A p93300012 -#PBS -l select=1:ncpus=4:mpiprocs=1 -#PBS -l walltime=05:00:00 -#PBS -q casper -#PBS -m abe - -./get_ocdata.sh > download_stderr.txt 2> download_stdout.txt \ No newline at end of file From 7e00f65603959b9daa0a0ef963c85f8fd72d3fc4 Mon Sep 17 00:00:00 2001 From: Moha El Gharamti Date: Fri, 30 Aug 2024 12:48:28 -0600 Subject: [PATCH 32/35] Improved Documentation Improved text in the documentation. New model interface and obs converter are now added to the toctree and can be accessed on docs.dart.edu --- guide/available-observation-converters.rst | 1 + index.rst | 2 ++ models/MARBL_column/readme.rst | 20 +++++++++++--------- models/README.rst | 1 + observations/obs_converters/BATS/readme.rst | 9 +++++---- observations/obs_converters/README.rst | 1 + 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/guide/available-observation-converters.rst b/guide/available-observation-converters.rst index 6b84da9cae..aa3b1cdc76 100644 --- a/guide/available-observation-converters.rst +++ b/guide/available-observation-converters.rst @@ -11,6 +11,7 @@ Each directory has at least one converter: - ``AURA``: See ``DART/observations/obs_converters/AURA`` - ``Aviso+/CMEMS``: :doc:`../observations/obs_converters/AVISO/AVISO` - ``Ameriflux``: :doc:`../observations/obs_converters/Ameriflux/level4_to_obs` +- ``BATS``: :doc:`../observations/obs_converters/BATS/readme` - ``CHAMP``: :doc:`../observations/obs_converters/CHAMP/work/README` - ``cice``: :doc:`../observations/obs_converters/cice/cice_to_obs` - ``CNOFS``: See ``DART/observations/obs_converters/CNOFS`` diff --git a/index.rst b/index.rst index 8b067e83fe..06b4686699 100644 --- a/index.rst +++ b/index.rst @@ -361,6 +361,7 @@ References observations/obs_converters/Ameriflux/fluxnetfull_to_obs observations/obs_converters/Ameriflux/level4_to_obs observations/obs_converters/CHAMP/work/README + observations/obs_converters/BATS/readme observations/obs_converters/cice/cice_to_obs observations/obs_converters/CONAGUA/README observations/obs_converters/COSMOS/COSMOS_to_obs @@ -466,6 +467,7 @@ References models/lorenz_96_tracer_advection/readme models/forced_lorenz_96/readme models/MITgcm_ocean/readme + models/MARBL_column/readme models/MOM6/readme models/mpas_atm/readme models/mpas_atm/mpas_dart_obs_preprocess diff --git a/models/MARBL_column/readme.rst b/models/MARBL_column/readme.rst index 406fc9d068..4130896276 100644 --- a/models/MARBL_column/readme.rst +++ b/models/MARBL_column/readme.rst @@ -24,25 +24,27 @@ It's designed to be used at locations where in-situ data is abundant such as The code is designed to perform 3 kinds of data assimilation (DA) experiments: #. **State Estimation:** where the prognostic state variables of MARBL such as nitrate concerntration are updated. - To achive this, you'll need to set - ``estimate_params = .false.`` within ``&model_nml`` in the namelist file ``input.nml`` + To achive this, you'll need to set + + ``estimate_params = .false.`` within ``&model_nml`` in the namelist file ``input.nml`` #. **State and Parameters Estimation:** where both the state and a set of model parameters are updated. MARBL has a long list of uncertain model parameters that can be constrained alongside the state. This usually improves the prediction skill of the model and alleviates some of its biases. To achieve this DA exercise, you'll need to set - ``estimate_params = .true.`` - - The combined DART state will be of the form :math:`Z_k = \left[ \mathbf{x}_k, \boldsymbol{\theta} \right]^T` - where :math:`Z_k` is the joint state, :math:`\mathbf{x}` and parameters, :math:`\boldsymbol{\theta}` - vector at time ``t_k`` + + ``estimate_params = .true.`` + + The combined DART state will be of the form :math:`Z_k = \left[ \mathbf{x}_k, \boldsymbol{\theta} \right]^T` + where :math:`Z_k` is the joint state, :math:`\mathbf{x}` and parameters, :math:`\boldsymbol{\theta}` + vector at time :math:`t_k` #. **Parameters Estimation only:** where only the parameters are constrained using the data. DART will still need to read in the state to construct ensemble covariances and compute innovations. The only difference is that the ensemble increments are only regressed onto the unknown parameters. To achive this goal, you'll need to set ``estimate_params = .true.`` and turn the update status for - all state variable to - ``NO_COPY_BACK`` + all state variable to ``NO_COPY_BACK`` + This ensures that the state will not be updated. The ``NO_COPY_BACK`` option is added as the 5th entry in the state table (after the variable name, its associated quantity and its physical bounds) within ``&model_nml`` diff --git a/models/README.rst b/models/README.rst index 73b4dd87bd..3e9f0d1a4a 100644 --- a/models/README.rst +++ b/models/README.rst @@ -31,6 +31,7 @@ DART supported models: - :doc:`MOM6/readme` - :doc:`mpas_atm/readme` - :doc:`mpas_ocn/readme` +- :doc:`MARBL_column/readme` - :doc:`NCOMMAS/readme` - :doc:`noah/readme` - :doc:`null_model/readme` diff --git a/observations/obs_converters/BATS/readme.rst b/observations/obs_converters/BATS/readme.rst index 97a2a0f99c..d72d34f9a3 100644 --- a/observations/obs_converters/BATS/readme.rst +++ b/observations/obs_converters/BATS/readme.rst @@ -17,7 +17,7 @@ often named ``bats_bottle.txt`` The data is huge extending from Oct 1988 to present day. It consists of a long list of information such as - Depth, Oxygen, CO2, Nitrate, Phosphate, Silicate, Alkalinity, Organic Carbon, Bacteria, ... +`Depth, Oxygen, CO2, Nitrate, Phosphate, Silicate, Alkalinity, Organic Carbon, Bacteria, ...` Observation Converter: ---------------------- @@ -53,7 +53,8 @@ Namelists start with an ampersand '&' and terminate with a slash '/'. This namelist provides control over the kind of observations to extract from the file in addition to their uncertainties. In its current form, the observations that are extracted from the data file are: - ``BATS_OXYGEN``, ``BATS_INORGANIC_CARBON``, ``BATS_ALKALINITY``, ``BATS_NITRATE``, ``BATS_PHOSPHATE``, ``BATS_SILICATE`` + +``BATS_OXYGEN``, ``BATS_INORGANIC_CARBON``, ``BATS_ALKALINITY``, ``BATS_NITRATE``, ``BATS_PHOSPHATE``, ``BATS_SILICATE`` +-------------------------------------+--------------------+------------------------------------------------------------+ | Contents | Type | Description | @@ -75,7 +76,7 @@ In its current form, the observations that are extracted from the data file are: +-------------------------------------+--------------------+------------------------------------------------------------+ | ``vert_cols`` | integer(2) | First and last columns where depth is recorded. | +-------------------------------------+--------------------+------------------------------------------------------------+ -| ``scalar_obs_cols `` | integer(:, 2) | ith row of this table should list the first and last | +| ``scalar_obs_cols`` | integer(:, 2) | ith row of this table should list the first and last | | | | columns where the value of the ith observation variable | | | | is recorded. Ordering of observation variables is defined | | | | by the OTYPE_ORDERING parameter in bats_to_obs.f90. | @@ -94,7 +95,7 @@ In its current form, the observations that are extracted from the data file are: +-------------------------------------+--------------------+------------------------------------------------------------+ Climatology: -~~~~~~~~~~~ +~~~~~~~~~~~~ On top of assimilating real-time data, we often observe the quasi-cyclostationary behavior of the biogeochemical system over the period of one year, and we update MARBL parameters by comparing this observed climatology to a climatology predicted by MARBL. This usually involves running different forms of the ensmeble smoother where the model is re-run diff --git a/observations/obs_converters/README.rst b/observations/obs_converters/README.rst index 0425020a93..151c326641 100644 --- a/observations/obs_converters/README.rst +++ b/observations/obs_converters/README.rst @@ -361,6 +361,7 @@ converters) include: - ``AURA``: See ``./AURA`` - ``Aviso+/CMEMS``: :doc:`./AVISO/AVISO` - ``Ameriflux``: :doc:`./Ameriflux/level4_to_obs` +- ``BATS``: :doc:`./BATS/readme` - ``CHAMP``: :doc:`./CHAMP/work/README` - ``cice``: :doc:`./cice/cice_to_obs` - ``CNOFS``: See ``./CNOFS`` From 48d6d599a188a43be5aa6a021c407197668522d6 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Tue, 3 Sep 2024 13:21:36 -0600 Subject: [PATCH 33/35] model-mod and documentation clean up Incorporated all suggestions and comments about model-mod. Several comments have been removed, redundant loc routines are omitted, better namelist parsing, deleted unused variables, ... --- models/MARBL_column/model_mod.f90 | 232 +++++++++-------------------- models/MARBL_column/readme.rst | 19 ++- models/MARBL_column/work/input.nml | 7 +- models/README.rst | 2 +- 4 files changed, 90 insertions(+), 170 deletions(-) diff --git a/models/MARBL_column/model_mod.f90 b/models/MARBL_column/model_mod.f90 index 86b51ddd2a..7c929a2a17 100644 --- a/models/MARBL_column/model_mod.f90 +++ b/models/MARBL_column/model_mod.f90 @@ -4,52 +4,47 @@ module model_mod -! This is a template showing the interfaces required for a model to be compliant -! with the DART data assimilation infrastructure. Do not change the arguments -! for the public routines. +! This is the MARBL_columun model_mod for the DART data assimilation infrastructure. +! Do not change the arguments for the public routines. -use types_mod, only : r8, i8, MISSING_R8, vtablenamelength +use types_mod, only : r8, i8, MISSING_R8, vtablenamelength -use time_manager_mod, only : time_type, set_time +use time_manager_mod, only : time_type, set_time -use location_mod, only : location_type, get_close_type, & - loc_get_close_obs => get_close_obs, & - loc_get_close_state => get_close_state, & - set_location, set_location_missing, & - get_location, VERTISLEVEL +use location_mod, only : location_type, get_close_type, & + get_close_obs, get_close_state, & + set_location, set_location_missing, & + get_location, VERTISLEVEL -use utilities_mod, only : register_module, error_handler, & - E_ERR, E_MSG, & - nmlfileunit, do_output, do_nml_file, do_nml_term, & - find_namelist_in_file, check_namelist_read, & - to_upper +use utilities_mod, only : error_handler, E_ERR, E_MSG, & + nmlfileunit, do_output, do_nml_file, do_nml_term, & + find_namelist_in_file, check_namelist_read, & + to_upper -use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & - nc_add_global_creation_time, & - nc_begin_define_mode, nc_end_define_mode, & - NF90_MAX_NAME, nc_open_file_readonly, & - nc_get_variable, nc_get_variable_size, nc_close_file +use netcdf_utilities_mod, only : nc_add_global_attribute, nc_synchronize_file, & + nc_add_global_creation_time, & + nc_begin_define_mode, nc_end_define_mode, & + NF90_MAX_NAME, nc_open_file_readonly, & + nc_get_variable, nc_get_variable_size, nc_close_file -use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & - get_varid_from_kind, get_dart_vector_index, & - get_num_domains +use state_structure_mod, only : add_domain, get_domain_size, get_model_variable_indices, & + get_varid_from_kind, get_dart_vector_index, & + get_num_domains -use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, & - QTY_V_CURRENT_COMPONENT, QTY_DRY_LAND, & - QTY_LAYER_THICKNESS +use obs_kind_mod, only : get_index_for_quantity, QTY_LAYER_THICKNESS -use distributed_state_mod, only: get_state +use distributed_state_mod, only : get_state -use ensemble_manager_mod, only : ensemble_type +use ensemble_manager_mod, only : ensemble_type ! These routines are passed through from default_model_mod. ! To write model specific versions of these routines ! remove the routine from this use statement and add your code to ! this the file. -use default_model_mod, only : pert_model_copies, write_model_time, & - init_time => fail_init_time, & - init_conditions => fail_init_conditions, & - convert_vertical_obs, convert_vertical_state, adv_1step +use default_model_mod, only : pert_model_copies, write_model_time, & + init_time => fail_init_time, & + init_conditions => fail_init_conditions, & + convert_vertical_obs, convert_vertical_state, adv_1step implicit none private @@ -62,9 +57,9 @@ module model_mod end_model, & static_init_model, & nc_write_model_atts, & + pert_model_copies, & get_close_obs, & get_close_state, & - pert_model_copies, & convert_vertical_obs, & convert_vertical_state, & read_model_time, & @@ -74,38 +69,40 @@ module model_mod shortest_time_between_assimilations, & write_model_time - character(len=256), parameter :: source = "model_mod.f90" -logical :: module_initialized = .false. -integer :: state_dom_id ! used to access the state structure -integer :: param_dom_id ! used to access MARBL internal parameters -integer :: nfields ! number of fields in the state or parameter vector -integer :: nz ! the number of vertical layers -integer :: model_size + +logical :: module_initialized = .false. +integer :: state_dom_id ! used to access the state structure +integer :: param_dom_id ! used to access MARBL internal parameters +integer :: nfields ! number of fields in the state or parameter vector +integer :: nz ! the number of vertical layers +integer(i8) :: model_size type(time_type) :: assimilation_time_step -real(r8) :: geolon -real(r8) :: geolat -real(r8) :: basin_depth(2,2) +real(r8) :: geolon +real(r8) :: geolat +real(r8) :: basin_depth(2,2) ! parameters to be used in specifying the DART internal state -integer, parameter :: modelvar_table_height = 13 -integer, parameter :: modelvar_table_width = 5 -integer, parameter :: modelparams_table_height = 1 -integer, parameter :: modelparams_table_width = 5 +integer, parameter :: MODELVAR_TABLE_HEIGHT = 13 +integer, parameter :: MODELVAR_TABLE_WIDTH = 5 +integer, parameter :: MODELPARAMS_TABLE_HEIGHT = 1 +integer, parameter :: MODELPARAMS_TABLE_WIDTH = 5 ! defining the variables that will be read from the namelist -character(len=256) :: template_file(2) -character(len=256) :: ocean_geometry -real(r8) :: station_location(2) -integer :: time_step_days -integer :: time_step_seconds -logical :: estimate_params -character(len=vtablenamelength) & - :: model_state_variables(modelvar_table_height * modelvar_table_width) -character(len=vtablenamelength) & - :: model_parameters(modelparams_table_height * modelparams_table_width) - -namelist /model_nml/ template_file, & +character(len=256) :: state_template_file = 'MOM.res.nc' +character(len=256) :: param_template_file = 'marbl_params.nc' +character(len=256) :: ocean_geometry = 'ocean_geometry.nc' +real(r8) :: station_location(2) = (/-64.0, 31.0/) +integer :: time_step_days = 1 +integer :: time_step_seconds = 0 +logical :: estimate_params = .false. +character(len=vtablenamelength) :: & + model_state_variables(MODELVAR_TABLE_HEIGHT * MODELVAR_TABLE_WIDTH) = '' +character(len=vtablenamelength) :: & + model_parameters(MODELPARAMS_TABLE_HEIGHT * MODELPARAMS_TABLE_WIDTH) = '' + +namelist /model_nml/ state_template_file, & + param_template_file, & ocean_geometry, & station_location, & time_step_days, & @@ -117,22 +114,19 @@ module model_mod !------------------------------------------------------------------ ! -! Called to do one time initialization of the model. As examples, -! might define information about the model size or model timestep. -! In models that require pre-computed static data, for instance -! spherical harmonic weights, these would also be computed here. +! Called to do one time initialization of the model. subroutine static_init_model() integer :: iunit, io, i_dom, domain_count -character(len=vtablenamelength) :: variable_table(modelvar_table_height, modelvar_table_width), & - param_table(modelparams_table_height, modelparams_table_width) -integer :: state_qty_list(modelvar_table_height), & - param_qty_list(modelparams_table_height) -real(r8):: state_clamp_vals(modelvar_table_height, 2), & - param_clamp_vals(modelparams_table_height, 2) -logical :: update_var_list(modelvar_table_height), & - update_param_list(modelparams_table_height) +character(len=vtablenamelength) :: variable_table(MODELVAR_TABLE_HEIGHT, MODELVAR_TABLE_WIDTH), & + param_table(MODELPARAMS_TABLE_HEIGHT, MODELPARAMS_TABLE_WIDTH) +integer :: state_qty_list(MODELVAR_TABLE_HEIGHT), & + param_qty_list(MODELPARAMS_TABLE_HEIGHT) +real(r8):: state_clamp_vals(MODELVAR_TABLE_HEIGHT, 2), & + param_clamp_vals(MODELPARAMS_TABLE_HEIGHT, 2) +logical :: update_var_list(MODELVAR_TABLE_HEIGHT), & + update_param_list(MODELPARAMS_TABLE_HEIGHT) module_initialized = .true. @@ -155,6 +149,12 @@ subroutine static_init_model() assimilation_time_step = set_time(time_step_seconds, & time_step_days) +! Make sure the longitude is properly assigned +geolon = station_location(1) +geolat = station_location(2) + +if (geolon < 0.0_r8) geolon = 360.0 + geolon + ! The kind of experiments that can be performed using this code: ! 1- State estimation: ! To achieve this, you'll need to set "estimate_params" @@ -173,7 +173,7 @@ subroutine static_init_model() call verify_state_variables(model_state_variables, nfields, variable_table, & state_qty_list, state_clamp_vals, update_var_list) - state_dom_id = add_domain(template_file(1), nfields, & + state_dom_id = add_domain(state_template_file, nfields, & var_names = variable_table(1:nfields, 1), & kind_list = state_qty_list(1:nfields), & clamp_vals = state_clamp_vals, & @@ -184,7 +184,7 @@ subroutine static_init_model() call verify_state_variables(model_parameters, nfields, param_table, & param_qty_list, param_clamp_vals, update_param_list) - param_dom_id = add_domain(template_file(2), nfields, & + param_dom_id = add_domain(param_template_file, nfields, & var_names = param_table(1:nfields, 1), & kind_list = param_qty_list(1:nfields), & clamp_vals = param_clamp_vals, & @@ -215,7 +215,6 @@ function read_model_time(filename) integer :: ncid character(len=*), parameter :: routine = 'read_model_time' real(r8) :: days -type(time_type) :: mom6_time integer :: mom_base_date_in_days, mom_days mom_base_date_in_days = 139157 ! 1982 1 1 0 0 @@ -289,10 +288,6 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! performing the interpolation for each ensemble member individually. do ens_index = 1, ens_size - !print *, "BASIN DEPTH = ",-basin_depth(1,1) - !print *, "----------------------------------------------------" - !print *, "computing centers of layers" - !print *, "----------------------------------------------------" ! locating the layer index to be used as the upper interpolation point for this ensemble member. layer_index = nz @@ -302,26 +297,17 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs layerdepth_top = layerdepth_bottom & ! depth at top of the layer given by layer_index. + layer_thicknesses(layer_index, ens_index) - !print *, "layer = ",layer_index,", center = ",layerdepth_center,", bottom = ",layerdepth_bottom,", top = ",layerdepth_top - do while((layerdepth_center < requested_depth) .and. (layer_index > 1)) layer_index = layer_index - 1 layerdepth_bottom = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) layerdepth_center = layerdepth_bottom + 0.5 * layer_thicknesses(layer_index, ens_index) layerdepth_top = layerdepth_bottom + layer_thicknesses(layer_index, ens_index) - - !print *, "layer = ",layer_index,", bottom = ",layerdepth_bottom,", center = ",layerdepth_center,", top = ",layerdepth_top - end do ! having located the index of the upper interpolation layer, we now calculate the interpolation. if((requested_depth < -basin_depth(1,1)) .or. (layerdepth_top < requested_depth)) then ! case where the requested depth is below the ocean floor, or above the ocean surface - !print *, "----------------------------------------------------" - !print *, "depth is below ocean floor or above ocean surface" - !print *, "----------------------------------------------------" - istatus(ens_index) = 1 expected_obs(ens_index) = MISSING_R8 @@ -330,25 +316,16 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs ! or the top half of the shallowest layer. In both cases, the "interpolated" value is ! simply the current value of that layer in MOM6. - !print *, "----------------------------------------------------" - !print *, "only using value from layer ", layer_index - !print *, "----------------------------------------------------" - istatus(ens_index) = 0 qty_index = get_dart_vector_index(1, 1, layer_index, state_dom_id, qty_id) state_slice = get_state(qty_index, state_handle) expected_obs(ens_index) = state_slice(ens_index) - ! print *, "final value = ",expected_obs(ens_index) - else ! case where the requested depth is above the center of some layer, and below ! the center of another. We interpolate linearly between the nearest layers above ! and below. - !print *, "----------------------------------------------------" - !print *, "interpolating between layers ", layer_index, " and ", (layer_index + 1) - istatus(ens_index) = 0 ! computing the depths at the centers of the nearest layers above and below @@ -365,13 +342,9 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs state_slice = get_state(qty_index, state_handle) val_below = state_slice(ens_index) - !print *, "corresponding to the values: ", val_above, " and ", val_below - !print *, "----------------------------------------------------" - ! linear interpolation expected_obs(ens_index) = val_above + (requested_depth - depth_above) * (val_below - val_above) / (depth_below - depth_above) - !print *, "final value = ",expected_obs(ens_index) end if end do @@ -411,12 +384,6 @@ subroutine get_state_meta_data(index_in, location, qty) call get_model_variable_indices(index_in, lon_index, lat_index, level, kind_index=local_qty) -! Make sure the longitude is properly assigned -geolon = station_location(1) -geolat = station_location(2) - -if (geolon < 0.0_r8) geolon = 360.0 + geolon - location = set_location(geolon, geolat, real(level,r8), VERTISLEVEL) if (present(qty)) then @@ -426,55 +393,6 @@ subroutine get_state_meta_data(index_in, location, qty) end subroutine get_state_meta_data -!------------------------------------------------------------------ -! Any model specific distance calcualtion can be done here -subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & - num_close, close_ind, dist, ens_handle) - -type(get_close_type), intent(in) :: gc ! handle to a get_close structure -integer, intent(in) :: base_type ! observation TYPE -type(location_type), intent(inout) :: base_loc ! location of interest -type(location_type), intent(inout) :: locs(:) ! obs locations -integer, intent(in) :: loc_qtys(:) ! QTYS for obs -integer, intent(in) :: loc_types(:) ! TYPES for obs -integer, intent(out) :: num_close ! how many are close -integer, intent(out) :: close_ind(:) ! incidies into the locs array -real(r8), optional, intent(out) :: dist(:) ! distances in radians -type(ensemble_type), optional, intent(in) :: ens_handle - -character(len=*), parameter :: routine = 'get_close_obs' - -call loc_get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, & - num_close, close_ind, dist, ens_handle) - -end subroutine get_close_obs - - -!------------------------------------------------------------------ -! Any model specific distance calcualtion can be done here -subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & - num_close, close_ind, dist, ens_handle) - -type(get_close_type), intent(in) :: gc ! handle to a get_close structure -type(location_type), intent(inout) :: base_loc ! location of interest -integer, intent(in) :: base_type ! observation TYPE -type(location_type), intent(inout) :: locs(:) ! state locations -integer, intent(in) :: loc_qtys(:) ! QTYs for state -integer(i8), intent(in) :: loc_indx(:) ! indices into DART state vector -integer, intent(out) :: num_close ! how many are close -integer, intent(out) :: close_ind(:) ! indices into the locs array -real(r8), optional, intent(out) :: dist(:) ! distances in radians -type(ensemble_type), optional, intent(in) :: ens_handle - -character(len=*), parameter :: routine = 'get_close_state' - - -call loc_get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, & - num_close, close_ind, dist, ens_handle) - - -end subroutine get_close_state - !------------------------------------------------------------------ ! write any additional attributes to the output and diagnostic files @@ -597,9 +515,7 @@ subroutine read_num_layers() integer :: ncid -character(len=*), parameter :: routine = 'read_num_layers' - -ncid = nc_open_file_readonly(template_file(1)) +ncid = nc_open_file_readonly(state_template_file) call nc_get_variable_size(ncid, 'Layer', nz) diff --git a/models/MARBL_column/readme.rst b/models/MARBL_column/readme.rst index 4130896276..abdf04e99f 100644 --- a/models/MARBL_column/readme.rst +++ b/models/MARBL_column/readme.rst @@ -45,8 +45,9 @@ The code is designed to perform 3 kinds of data assimilation (DA) experiments: To achive this goal, you'll need to set ``estimate_params = .true.`` and turn the update status for all state variable to ``NO_COPY_BACK`` - This ensures that the state will not be updated. The ``NO_COPY_BACK`` option is added as the 5th entry - in the state table (after the variable name, its associated quantity and its physical bounds) within ``&model_nml`` + This ensures that the updated state will not be written back to the restart file. The ``NO_COPY_BACK`` + option is added as the 5th entry in the state table (after the variable name, its associated quantity + and its physical bounds) within ``&model_nml``. Namelist -------- @@ -55,8 +56,9 @@ The ``&model_nml`` variables and their default values are listed here: .. code-block:: fortran &model_nml - template_file = 'member_0001/RESTART/MOM.res.nc', 'member_0001/marbl_params.nc', - ocean_geometry = 'member_0001/ocean_geometry.nc', + state_template_file = 'MOM.res.nc', + param_template_file = 'marbl_params.nc', + ocean_geometry = 'ocean_geometry.nc', station_location = -64, 31 time_step_days = 1, time_step_seconds = 0, @@ -82,13 +84,14 @@ This namelist provides control over the kind of DA experiment as described abvov +-------------------------------------+--------------------+------------------------------------------------------------+ | Item | Type | Description | +=====================================+====================+============================================================+ -| ``template_file`` | character(len=256) | MARBL restart file including MARBL's prognostic variables | +| ``state_template_file`` | character(len=256) | MARBL restart file including MARBL's prognostic variables | | | | and other grid information such as the ocean layers. | | | | The state variables read from this file are listed in | | | | in the ``model_state_variables`` | -| | | | -| | | There is another template file corresponding to the | -| | | BGC parameters that we intend to estimate. | ++-------------------------------------+--------------------+------------------------------------------------------------+ +| ``param_template_file`` | character(len=256) | Template file corresponding to the BGC parameters that we | +| | | intend to estimate. The parameters read from this file are | +| | | listed in the ``model_parameters``. | +-------------------------------------+--------------------+------------------------------------------------------------+ | ``ocean_geometry`` | character(len=256) | The ocean geometry file is used to read ``basin_depth`` | +-------------------------------------+--------------------+------------------------------------------------------------+ diff --git a/models/MARBL_column/work/input.nml b/models/MARBL_column/work/input.nml index d76881e769..c2c1035f47 100644 --- a/models/MARBL_column/work/input.nml +++ b/models/MARBL_column/work/input.nml @@ -7,7 +7,8 @@ / &model_nml - template_file = 'ensemble/background/member_0001/RESTART/MOM.res.nc', 'ensemble/background/member_0001/marbl_params.nc', + state_template_file = 'ensemble/background/member_0001/RESTART/MOM.res.nc', + param_template_file = 'ensemble/background/member_0001/marbl_params.nc', ocean_geometry = 'ensemble/background/member_0001/ocean_geometry.nc', station_location = -64, 31 time_step_days = 1, @@ -236,8 +237,8 @@ / &model_mod_check_nml - input_state_files = 'mom_in.nc', 'param_in.nc' - output_state_files = 'mom_out.nc', 'param_out.nc' + input_state_files = 'marbl_in.nc', 'param_in.nc' + output_state_files = 'marbl_out.nc', 'param_out.nc' test1thru = 7 run_tests = 1 x_ind = 600 diff --git a/models/README.rst b/models/README.rst index 3e9f0d1a4a..932d60424e 100644 --- a/models/README.rst +++ b/models/README.rst @@ -27,11 +27,11 @@ DART supported models: - :doc:`lorenz_96_2scale/readme` - :doc:`lorenz_96_tracer_advection/readme` - :doc:`forced_lorenz_96/readme` +- :doc:`MARBL_column/readme` - :doc:`MITgcm_ocean/readme` - :doc:`MOM6/readme` - :doc:`mpas_atm/readme` - :doc:`mpas_ocn/readme` -- :doc:`MARBL_column/readme` - :doc:`NCOMMAS/readme` - :doc:`noah/readme` - :doc:`null_model/readme` From e3e1b936382ad9054455d15da08dbf35aa8e70b6 Mon Sep 17 00:00:00 2001 From: Mohamad Gharamti Date: Wed, 4 Sep 2024 12:33:47 -0600 Subject: [PATCH 34/35] Obs Converter Clean up Did a cleanup of the obs converter: - Removed comments - Removed unused variables - Improved style - Better use of DART's modules - Improved initialization and functions - Ran and tested the converter after the changes were made --- .../observations/default_quantities_mod.f90 | 15 -- .../obs_converters/BATS/bats_climatology.py | 80 ++++---- .../obs_converters/BATS/bats_to_clim_obs.f90 | 151 ++------------- .../obs_converters/BATS/bats_to_obs.f90 | 172 +++--------------- .../obs_converters/BATS/work/input.nml | 2 +- 5 files changed, 79 insertions(+), 341 deletions(-) diff --git a/assimilation_code/modules/observations/default_quantities_mod.f90 b/assimilation_code/modules/observations/default_quantities_mod.f90 index 2e8cd2278f..ebc2d068e9 100644 --- a/assimilation_code/modules/observations/default_quantities_mod.f90 +++ b/assimilation_code/modules/observations/default_quantities_mod.f90 @@ -387,22 +387,7 @@ ! QTY_WIND_TURBINE_POWER ! QTY_W_CURRENT_COMPONENT ! QTY_X_LAMBDA -! QTY_NITRATE_CONCENTRATION -! QTY_PHOSPHATE_CONCENTRATION -! QTY_DISSOLVED_OXYGEN -! QTY_PHYTOPLANKTON_BIOMASS -! QTY_ALKALINITY -! QTY_DISSOLVED_INORGANIC_CARBON -! QTY_DISSOLVED_ORGANIC_CARBON -! QTY_DISSOLVED_ORGANIC_NITROGEN -! QTY_DISSOLVED_ORGANIC_P -! QTY_DISSOLVED_INORGANIC_IRON -! QTY_SURFACE_CHLOROPHYLL -! QTY_LAYER_THICKNESS ! QTY_COLUMN_DEPTH -! QTY_DISSOLVED_INORGANIC_SIO3 -! QTY_MESOZOOPLANKTON_CARBON -! QTY_MICROZOOPLANKTON_CARBON ! QTY_BGC_PARAM ! ! END DART PREPROCESS QUANTITY DEFINITIONS diff --git a/observations/obs_converters/BATS/bats_climatology.py b/observations/obs_converters/BATS/bats_climatology.py index 4978775e07..a184869133 100644 --- a/observations/obs_converters/BATS/bats_climatology.py +++ b/observations/obs_converters/BATS/bats_climatology.py @@ -1,4 +1,4 @@ -import os +#!/usr/bin/env python3 import numpy as np import netCDF4 as nc import matplotlib.pyplot as plt @@ -8,23 +8,23 @@ ################################################################# # input and output datafiles -input_file_path = 'data/bats_bottle.txt' -output_txt_path = 'data/bats_climatology.txt' -output_nc_path = 'data/bats_climatology.nc' +input_file_path = 'bats_bottle.txt' +output_txt_path = 'bats_climatology.txt' +output_nc_path = 'bats_climatology.nc' first_data_line = 61 # file is read starting at this line (so that header information is ignored) month_columns = [18, 19] # first and last columns in the data file containing month values -depth_columns = [58, 63] # first and last columns in the data file containing depth values +depth_columns = [64, 69] # first and last columns in the data file containing depth values num_obs_types = 6 # number of variables being read from the datafile max_num_data = 16660 # upper bound on the number of data points to be processed # first and last columns in the data file containing values for each variable -obs_val_columns = [[102, 107], # O2 - [126, 131], # CO2 - [134, 139], # Alk - [141, 147], # NO31 - [158, 164], # PO41 - [166, 172]] # Si1 +obs_val_columns = [[113, 119], # O2 + [137, 143], # CO2 + [145, 151], # Alk + [153, 159], # NO31 + [170, 176], # PO41 + [178, 184]] # Si1 # layer interface depths for data in prog_z.nc output file from MARBL, run "ncdump -v "z_i" prog_z.nc" to generate. marbl_depths = [0, 5, 15, 25, 40, 62.5, 87.5, 112.5, 137.5, 175, 225, 275, 350, 450, @@ -45,57 +45,43 @@ sq_means = np.zeros((num_obs_types, 12, len(marbl_depths))) sample_counts = np.zeros((num_obs_types, 12, len(marbl_depths)), dtype=int) -bats_data = open(input_file_path, "r") -line_number = 0 - -for line in bats_data.readlines(): - line_number += 1 - - if(line_number < first_data_line): - continue +with open(input_file_path, "r") as bats_data: + for line in bats_data.readlines()[first_data_line-1:]: - # extracting the depth and month where this observation was taken - - depth_val = float(line[depth_columns[0]-1:depth_columns[1]]) - month_index = int(line[month_columns[0]-1:month_columns[1]]) - 1 + # extracting the depth and month where this observation was taken + depth_val = float(line[depth_columns[0]-1:depth_columns[1]]) + month_index = int(line[month_columns[0]-1:month_columns[1]]) - 1 - # assigning this observation to one of the MARBL layers - - depth_index = len(marbl_depths) - 1 + # assigning this observation to one of the MARBL layers + depth_index = len(marbl_depths) - 1 - while((depth_val < marbl_depths[depth_index]) and (depth_index > 0)): - depth_index -= 1 + while((depth_val < marbl_depths[depth_index]) and (depth_index > 0)): + depth_index -= 1 - # adding this observation into the climatology - - for obs_type_index in range(num_obs_types): - obs_val = float(line[obs_val_columns[obs_type_index][0]-1:obs_val_columns[obs_type_index][1]]) + # adding this observation into the climatology + for obs_type_index in range(num_obs_types): + obs_val = float(line[obs_val_columns[obs_type_index][0]-1:obs_val_columns[obs_type_index][1]]) - if(abs(obs_val + 999.0) > 1e-8): # this filters out 'missing' values - prev_mean = clim_means[obs_type_index, month_index, depth_index] - prev_sqmean = sq_means[obs_type_index, month_index, depth_index] - prev_samples = sample_counts[obs_type_index, month_index, depth_index] + if(abs(obs_val + 999.0) > 1e-8): # this filters out 'missing' values + prev_mean = clim_means[obs_type_index, month_index, depth_index] + prev_sqmean = sq_means[obs_type_index, month_index, depth_index] + prev_samples = sample_counts[obs_type_index, month_index, depth_index] - new_mean = (prev_samples*prev_mean + obs_val)/(prev_samples + 1) - new_sqmean = (prev_samples*prev_sqmean + obs_val**2)/(prev_samples + 1) + new_mean = (prev_samples*prev_mean + obs_val)/(prev_samples + 1) + new_sqmean = (prev_samples*prev_sqmean + obs_val**2)/(prev_samples + 1) - clim_means[obs_type_index, month_index, depth_index] = new_mean - sq_means[obs_type_index, month_index, depth_index] = new_sqmean + clim_means[obs_type_index, month_index, depth_index] = new_mean + sq_means[obs_type_index, month_index, depth_index] = new_sqmean - sample_counts[obs_type_index, month_index, depth_index] += 1 + sample_counts[obs_type_index, month_index, depth_index] += 1 - print("month =",month_index,", type =",obs_type_index,", depth =",marbl_depths[depth_index],", value =",obs_val) + print("month =",month_index,", type =",obs_type_index,", depth =",marbl_depths[depth_index],", value =",obs_val) -bats_data.close() # setting up a CSV file to write the climatology into; this will be read by the DART data converter. - -os.system("rm -f "+output_txt_path) output_txt = open(output_txt_path, "w") # setting up a netCDF file to write the climatology into; this will be useful for creating MARBL-DART diagnostics. - -os.system("rm -f "+output_nc_path) output_nc = nc.Dataset(output_nc_path, "w") output_nc.createDimension("Month") diff --git a/observations/obs_converters/BATS/bats_to_clim_obs.f90 b/observations/obs_converters/BATS/bats_to_clim_obs.f90 index c9db561c89..60d1ad2b42 100644 --- a/observations/obs_converters/BATS/bats_to_clim_obs.f90 +++ b/observations/obs_converters/BATS/bats_to_clim_obs.f90 @@ -2,7 +2,6 @@ ! by UCAR, "as is", without charge, subject to all terms of use at ! http://www.image.ucar.edu/DAReS/DART/DART_download ! -! $Id$ ! This file is meant to read a text file containing bottle data from the ! Bermuda Atlantic Time-Series Study (https://bats.bios.asu.edu/), which @@ -10,7 +9,7 @@ program bats_to_clim_obs -use types_mod, only : r8, PI, DEG2RAD +use types_mod, only : r8 use utilities_mod, only : initialize_utilities, finalize_utilities, & open_file, close_file, & find_namelist_in_file, check_namelist_read, & @@ -18,14 +17,14 @@ program bats_to_clim_obs do_nml_file, do_nml_term use time_manager_mod, only : time_type, set_calendar_type, set_date, & operator(>=), increment_time, get_time, & - operator(-), NOLEAP, GREGORIAN, operator(+), & + operator(-), GREGORIAN, operator(+), & print_date use location_mod, only : VERTISHEIGHT, VERTISPRESSURE use obs_sequence_mod, only : obs_sequence_type, obs_type, read_obs_seq, & static_init_obs_sequence, init_obs, write_obs_seq, & init_obs_sequence, get_num_obs, set_copy_meta_data, & set_qc_meta_data, destroy_obs_sequence - +use obs_utilities_mod, only : create_3d_obs, add_obs_to_seq use obs_kind_mod, only : BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, & BATS_NITRATE, BATS_PHOSPHATE, BATS_SILICATE @@ -40,14 +39,15 @@ program bats_to_clim_obs BATS_PHOSPHATE, BATS_SILICATE/) real(r8), parameter :: MIN_OBS_ERROR = 0.1_r8 -real(r8), parameter :: bats_lon = 360.0_r8 - 64.0_r8 -real(r8), parameter :: bats_lat = 31.0_r8 +real(r8), parameter :: BATS_LON = 360.0_r8 - 64.0_r8 +real(r8), parameter :: BATS_LAT = 31.0_r8 ! namelist variables, changeable at runtime -character(len=256) :: text_input_file, obs_out_dir -integer :: max_lines -real(r8) :: obs_err_var_inflation -logical :: debug +character(len=256) :: text_input_file = 'bats_climatology.txt' +character(len=256) :: obs_out_dir = 'obs_seq_files' +integer :: max_lines = 3000 +real(r8) :: obs_err_var_inflation = 10.0 +logical :: debug = .true. namelist /bats_to_clim_obs_nml/ text_input_file, max_lines, obs_err_var_inflation, obs_out_dir, debug @@ -55,16 +55,13 @@ program bats_to_clim_obs character (len=294) :: input_line, obs_out_file character (len=6) :: month_str -integer :: oday, osec, rcio, iunit, otype, char_index, comma_index, line_number, otype_index, & - year, month, month_old, day, hour, minute, second, num_copies, num_qc, max_obs -integer :: comma_locs(4) - +integer :: oday, osec, rcio, iunit, char_index, comma_index, line_number, otype_index, & + month, month_old, num_copies, num_qc, max_obs +integer :: comma_locs(4) logical :: first_obs, new_obs_seq real(r8) :: qc, obs_err -real(r8) :: lat, lon, vert, ovalue - -! the uncertainties corresponding to the observations above +real(r8) :: vert, ovalue type(obs_sequence_type) :: obs_seq type(obs_type) :: obs, prev_obs @@ -229,7 +226,7 @@ program bats_to_clim_obs end if ! adding the observation - call create_3d_obs(bats_lat, bats_lon, vert, VERTISHEIGHT, & + call create_3d_obs(BATS_LAT, BATS_LON, vert, VERTISHEIGHT, & ovalue, OTYPE_ORDERING(otype_index), obs_err, & oday, osec, qc, obs) @@ -247,122 +244,4 @@ program bats_to_clim_obs ! end of main program call finalize_utilities() -contains - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! -! create_3d_obs - subroutine that is used to create an observation -! type from observation data. -! -! NOTE: assumes the code is using the threed_sphere locations module, -! that the observation has a single data value and a single -! qc value, and that this obs type has no additional required -! data (e.g. gps and radar obs need additional data per obs) -! -! inputs: -! lat - latitude of observation -! lon - longitude of observation -! vval - vertical coordinate -! vkind - kind of vertical coordinate (pressure, level, etc) -! obsv - observation value -! otype - observation type -! oerr - observation error -! day - gregorian day -! sec - gregorian second -! qc - quality control value -! outputs: -! obs - observation type -! -! created Oct. 2007 Ryan Torn, NCAR/MMM -! adapted for more generic use 11 Mar 2010, nancy collins, ncar/image -! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine create_3d_obs(lat, lon, vval, vkind, obsv, otype, oerr, day, sec, qc, obs) -use types_mod, only : r8 -use obs_def_mod, only : obs_def_type, set_obs_def_time, set_obs_def_type_of_obs, & - set_obs_def_error_variance, set_obs_def_location -use obs_sequence_mod, only : obs_type, set_obs_values, set_qc, set_obs_def -use time_manager_mod, only : time_type, set_time -use location_mod, only : set_location - - integer, intent(in) :: otype, vkind, day, sec - real(r8), intent(in) :: lat, lon, vval, obsv, oerr, qc - type(obs_type), intent(inout) :: obs - -real(r8) :: obs_val(1), qc_val(1) -type(obs_def_type) :: obs_def - -call set_obs_def_location(obs_def, set_location(lon, lat, vval, vkind)) -call set_obs_def_type_of_obs(obs_def, otype) -call set_obs_def_time(obs_def, set_time(sec, day)) -call set_obs_def_error_variance(obs_def, oerr * oerr) -call set_obs_def(obs, obs_def) - -obs_val(1) = obsv -call set_obs_values(obs, obs_val) -qc_val(1) = qc -call set_qc(obs, qc_val) - -end subroutine create_3d_obs - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! -! add_obs_to_seq -- adds an observation to a sequence. inserts if first -! obs, inserts with a prev obs to save searching if that's possible. -! -! seq - observation sequence to add obs to -! obs - observation, already filled in, ready to add -! obs_time - time of this observation, in dart time_type format -! prev_obs - the previous observation that was added to this sequence -! (will be updated by this routine) -! prev_time - the time of the previously added observation -! (will also be updated by this routine) -! first_obs - should be initialized to be .true., and then will be -! updated by this routine to be .false. after the first obs -! has been added to this sequence. -! -! created Mar 8, 2010 nancy collins, ncar/image -! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine add_obs_to_seq(seq, obs, obs_time, prev_obs, prev_time, first_obs) - use types_mod, only : r8 - use obs_sequence_mod, only : obs_sequence_type, obs_type, insert_obs_in_seq - use time_manager_mod, only : time_type, operator(>=) - - type(obs_sequence_type), intent(inout) :: seq - type(obs_type), intent(inout) :: obs, prev_obs - type(time_type), intent(in) :: obs_time - type(time_type), intent(inout) :: prev_time - logical, intent(inout) :: first_obs - -! insert(seq,obs) always works (i.e. it inserts the obs in -! proper time format) but it can be slow with a long file. -! supplying a previous observation that is older (or the same -! time) as the new one speeds up the searching a lot. - -if(first_obs) then ! for the first observation, no prev_obs - call insert_obs_in_seq(seq, obs) - first_obs = .false. -else - if(obs_time >= prev_time) then ! same time or later than previous obs - call insert_obs_in_seq(seq, obs, prev_obs) - else ! earlier, search from start of seq - call insert_obs_in_seq(seq, obs) - endif -endif - -! update for next time -prev_obs = obs -prev_time = obs_time - -end subroutine add_obs_to_seq - end program bats_to_clim_obs - -! -! $URL$ -! $Id$ -! $Revision$ -! $Date$ diff --git a/observations/obs_converters/BATS/bats_to_obs.f90 b/observations/obs_converters/BATS/bats_to_obs.f90 index 083225c65d..e6e0059206 100644 --- a/observations/obs_converters/BATS/bats_to_obs.f90 +++ b/observations/obs_converters/BATS/bats_to_obs.f90 @@ -2,14 +2,13 @@ ! by UCAR, "as is", without charge, subject to all terms of use at ! http://www.image.ucar.edu/DAReS/DART/DART_download ! -! $Id$ ! This file is meant to read a text file containing bottle data from the ! Bermuda Atlantic Time-Series Study (https://bats.bios.asu.edu/). program bats_to_obs -use types_mod, only : r8, PI, DEG2RAD +use types_mod, only : r8 use utilities_mod, only : initialize_utilities, finalize_utilities, & open_file, close_file, & find_namelist_in_file, check_namelist_read, & @@ -17,14 +16,14 @@ program bats_to_obs do_nml_file, do_nml_term use time_manager_mod, only : time_type, set_calendar_type, set_date, & operator(>=), increment_time, get_time, & - operator(-), NOLEAP, GREGORIAN, operator(+), & + operator(-), GREGORIAN, operator(+), & print_date use location_mod, only : VERTISHEIGHT, VERTISPRESSURE use obs_sequence_mod, only : obs_sequence_type, obs_type, read_obs_seq, & static_init_obs_sequence, init_obs, write_obs_seq, & init_obs_sequence, get_num_obs, set_copy_meta_data, & set_qc_meta_data, destroy_obs_sequence - +use obs_utilities_mod, only : create_3d_obs, add_obs_to_seq use obs_kind_mod, only : BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, & BATS_NITRATE, BATS_PHOSPHATE, BATS_SILICATE @@ -35,22 +34,31 @@ program bats_to_obs ! this array defines the order in which observations are read from the file integer, parameter :: OTYPE_ORDERING(NUM_SCALAR_OBS) & - = (/BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, BATS_NITRATE, & + = (/BATS_OXYGEN, BATS_INORGANIC_CARBON, BATS_ALKALINITY, BATS_NITRATE, & BATS_PHOSPHATE, BATS_SILICATE/) real(r8), parameter :: MIN_OBS_ERROR = 0.1_r8 -real(r8), parameter :: bats_lon = 360.0_r8 - 64.0_r8 -real(r8), parameter :: bats_lat = 31.0_r8 +real(r8), parameter :: BATS_LON = 360.0_r8 - 64.0_r8 +real(r8), parameter :: BATS_LAT = 31.0_r8 ! namelist variables, changeable at runtime -character(len=256) :: text_input_file, obs_out_dir -integer :: max_lines, read_starting_at_line, date_firstcol, hourminute_firstcol -integer :: lat_cols(2), lon_cols(2), vert_cols(2) -integer :: scalar_obs_cols(2, NUM_SCALAR_OBS) -real(r8) :: obs_uncertainties(NUM_SCALAR_OBS) -logical :: debug - -namelist /bats_to_obs_nml/ text_input_file, max_lines, read_starting_at_line, date_firstcol, & +character(len=256) :: text_input_file = 'bats_bottle.txt' +character(len=256) :: obs_out_dir = 'obs_seq_files' +integer :: max_lines = 68000 +integer :: read_starting_at_line = 61 +integer :: date_firstcol = 14 +integer :: hourminute_firstcol = 35 +integer :: lat_cols(2) = (/42, 47/) +integer :: lon_cols(2) = (/51, 56/) +integer :: vert_cols(2) = (/64, 69/) +real(r8) :: obs_uncertainties(NUM_SCALAR_OBS) = 0.2_r8 +logical :: debug = .true. +integer :: scalar_obs_cols(2, NUM_SCALAR_OBS) = reshape( (/ & + 113, 137, 145, 153, 170, 178, & + 119, 143, 151, 159, 176, 184 /), & + shape(scalar_obs_cols), order=(/2,1/) ) + +namelist /bats_to_obs_nml/ text_input_file, max_lines, read_starting_at_line, date_firstcol, & hourminute_firstcol, lat_cols, lon_cols, vert_cols, scalar_obs_cols, & obs_uncertainties, obs_out_dir, debug @@ -58,23 +66,21 @@ program bats_to_obs character (len=294) :: input_line, obs_out_file character (len=6) :: daystr -integer :: oday, day_bin, day_bin_old, osec, rcio, iunit, otype, line_number, otype_index -integer :: year, month, day, hour, minute, second, hourminute_raw, date_raw +integer :: oday, day_bin, day_bin_old, osec, rcio, iunit, line_number, otype_index +integer :: year, month, day, hour, minute, hourminute_raw, date_raw integer :: num_copies, num_qc, max_obs integer :: num_processed(NUM_SCALAR_OBS) -logical :: file_exist, first_obs, new_obs_seq +logical :: first_obs, new_obs_seq -real(r8) :: temp, terr, qc, wdir, wspeed, werr, obs_err -real(r8) :: lat, lon, vert, uwnd, uerr, vwnd, verr, ovalue +real(r8) :: qc, obs_err +real(r8) :: vert, ovalue real(r8) :: running_sum(NUM_SCALAR_OBS), running_sqsum(NUM_SCALAR_OBS), & maxvals(NUM_SCALAR_OBS), minvals(NUM_SCALAR_OBS) -! the uncertainties corresponding to the observations above - type(obs_sequence_type) :: obs_seq type(obs_type) :: obs, prev_obs -type(time_type) :: ref_day0, time_obs, prev_time +type(time_type) :: time_obs, prev_time ! start of executable code @@ -280,7 +286,7 @@ program bats_to_obs obs_err = max(obs_uncertainties(otype_index)*ovalue, MIN_OBS_ERROR) - call create_3d_obs(bats_lat, bats_lon, vert, VERTISHEIGHT, & + call create_3d_obs(BATS_LAT, BATS_LON, vert, VERTISHEIGHT, & ovalue, OTYPE_ORDERING(otype_index), obs_err, & oday, osec, qc, obs) @@ -314,122 +320,4 @@ program bats_to_obs ! end of main program call finalize_utilities() -contains - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! -! create_3d_obs - subroutine that is used to create an observation -! type from observation data. -! -! NOTE: assumes the code is using the threed_sphere locations module, -! that the observation has a single data value and a single -! qc value, and that this obs type has no additional required -! data (e.g. gps and radar obs need additional data per obs) -! -! inputs: -! lat - latitude of observation -! lon - longitude of observation -! vval - vertical coordinate -! vkind - kind of vertical coordinate (pressure, level, etc) -! obsv - observation value -! otype - observation type -! oerr - observation error -! day - gregorian day -! sec - gregorian second -! qc - quality control value -! outputs: -! obs - observation type -! -! created Oct. 2007 Ryan Torn, NCAR/MMM -! adapted for more generic use 11 Mar 2010, nancy collins, ncar/image -! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine create_3d_obs(lat, lon, vval, vkind, obsv, otype, oerr, day, sec, qc, obs) -use types_mod, only : r8 -use obs_def_mod, only : obs_def_type, set_obs_def_time, set_obs_def_type_of_obs, & - set_obs_def_error_variance, set_obs_def_location -use obs_sequence_mod, only : obs_type, set_obs_values, set_qc, set_obs_def -use time_manager_mod, only : time_type, set_time -use location_mod, only : set_location - - integer, intent(in) :: otype, vkind, day, sec - real(r8), intent(in) :: lat, lon, vval, obsv, oerr, qc - type(obs_type), intent(inout) :: obs - -real(r8) :: obs_val(1), qc_val(1) -type(obs_def_type) :: obs_def - -call set_obs_def_location(obs_def, set_location(lon, lat, vval, vkind)) -call set_obs_def_type_of_obs(obs_def, otype) -call set_obs_def_time(obs_def, set_time(sec, day)) -call set_obs_def_error_variance(obs_def, oerr * oerr) -call set_obs_def(obs, obs_def) - -obs_val(1) = obsv -call set_obs_values(obs, obs_val) -qc_val(1) = qc -call set_qc(obs, qc_val) - -end subroutine create_3d_obs - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! -! add_obs_to_seq -- adds an observation to a sequence. inserts if first -! obs, inserts with a prev obs to save searching if that's possible. -! -! seq - observation sequence to add obs to -! obs - observation, already filled in, ready to add -! obs_time - time of this observation, in dart time_type format -! prev_obs - the previous observation that was added to this sequence -! (will be updated by this routine) -! prev_time - the time of the previously added observation -! (will also be updated by this routine) -! first_obs - should be initialized to be .true., and then will be -! updated by this routine to be .false. after the first obs -! has been added to this sequence. -! -! created Mar 8, 2010 nancy collins, ncar/image -! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine add_obs_to_seq(seq, obs, obs_time, prev_obs, prev_time, first_obs) - use types_mod, only : r8 - use obs_sequence_mod, only : obs_sequence_type, obs_type, insert_obs_in_seq - use time_manager_mod, only : time_type, operator(>=) - - type(obs_sequence_type), intent(inout) :: seq - type(obs_type), intent(inout) :: obs, prev_obs - type(time_type), intent(in) :: obs_time - type(time_type), intent(inout) :: prev_time - logical, intent(inout) :: first_obs - -! insert(seq,obs) always works (i.e. it inserts the obs in -! proper time format) but it can be slow with a long file. -! supplying a previous observation that is older (or the same -! time) as the new one speeds up the searching a lot. - -if(first_obs) then ! for the first observation, no prev_obs - call insert_obs_in_seq(seq, obs) - first_obs = .false. -else - if(obs_time >= prev_time) then ! same time or later than previous obs - call insert_obs_in_seq(seq, obs, prev_obs) - else ! earlier, search from start of seq - call insert_obs_in_seq(seq, obs) - endif -endif - -! update for next time -prev_obs = obs -prev_time = obs_time - -end subroutine add_obs_to_seq - end program bats_to_obs - -! -! $URL$ -! $Id$ -! $Revision$ -! $Date$ diff --git a/observations/obs_converters/BATS/work/input.nml b/observations/obs_converters/BATS/work/input.nml index bcca4c032d..165b306376 100644 --- a/observations/obs_converters/BATS/work/input.nml +++ b/observations/obs_converters/BATS/work/input.nml @@ -25,7 +25,7 @@ / &bats_to_clim_obs_nml - text_input_file = "../data/bats_climatology.txt" + text_input_file = "../bats_climatology.txt" max_lines = 3000 obs_err_var_inflation = 10 obs_out_dir = '../obs_seq_files', From 7cc0befdfcfacd117255a1afb27ace76ab073240 Mon Sep 17 00:00:00 2001 From: Helen Kershaw Date: Tue, 10 Sep 2024 14:23:00 -0400 Subject: [PATCH 35/35] bump version and changelog for release --- CHANGELOG.rst | 16 ++++++++++++++++ conf.py | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ea49e40a59..d31552f944 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -22,6 +22,22 @@ individual files. The changes are now listed with the most recent at the top. +**September 10 2024:: MARBL_column. Tag 11.8.0** + +- Interface for MARBL_column for DART: + + - state estimation + - state and parameter estimation + - parameter estimation only + +- BATS observation converter, and BATS climatology scripting + +*contributed by Robin Armstrong* + +Bugfix: + +- fix for IO for NetCDF files when only some variables have the unlimited dimension + **August 29 2024 :: Bug fixes for shortest_time_between_assimilations and get_close_init. Tag 11.7.1** Bug fixes: diff --git a/conf.py b/conf.py index 7d4d9a8f4f..833c43425d 100644 --- a/conf.py +++ b/conf.py @@ -21,7 +21,7 @@ author = 'Data Assimilation Research Section' # The full version, including alpha/beta/rc tags -release = '11.7.1' +release = '11.8.0' root_doc = 'index' # -- General configuration ---------------------------------------------------