Skip to content

Commit

Permalink
Merge branch 'develop' into feature/ygyu/NPW_1_file
Browse files Browse the repository at this point in the history
  • Loading branch information
metdyn committed Jan 6, 2025
2 parents 8b633dc + c8ad63f commit f51b43a
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 16 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added optional start_date and start_time to control the output window for each History collection. No output will be written before then. If not specified, these default to the beginning of the experiment.
- Added utility to prepare inputs for ExtDatDriver.x so that ExtData can simulate a real GEOS run
- Added loggers when writing or reading weight files
- Added new option to AGCM.rc `overwrite_checkpoint` to allow checkpoint files to be overwritten. By default still will not overwrite checkpoints
- Added use_NWP_1_file=1 option in Trajectory sampler (HISTORY.rc) to generate the correct location_index_ioda array, mapping back to location points in the single IODA observation input file

### Changed

- Changed MAPL_ESMFRegridder to require the dstMaskValues to be added as grid attribute to use fixed masking, fixes UFS issue
- Increased formatting width of time index in ExtData2G diagnostic print

### Fixed
Expand Down
58 changes: 58 additions & 0 deletions Tests/generate_extdatadriver_input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Introduction
This is a simple utility to generate inputs for ExtDataDriver.x so that ExtData can simulate a real GEOS run. It requires 3 things that are passed in
- A list of items ExtData needs to fill. This can be found by looking at the GEOS log
- The import spec of the GCM component from using the printspec option to GEOS
- all the needed yaml files in a directory, name of directory is passed

This will generate the import and optionally the export (as well as History) defition for ExtDataDriver.x to spare the human the tedious work.

# Example Inputs
To get the list of ExtDate items, just grab all the lines that look like this to a file:
```
EXTDATA: INFO: ---- 00001: BC_AIRCRAFT
EXTDATA: INFO: ---- 00002: BC_ANTEBC1
EXTDATA: INFO: ---- 00003: BC_ANTEBC2
EXTDATA: INFO: ---- 00004: BC_AVIATION_CDS
EXTDATA: INFO: ---- 00005: BC_AVIATION_CRS
EXTDATA: INFO: ---- 00006: BC_AVIATION_LTO
EXTDATA: INFO: ---- 00007: BC_BIOFUEL
EXTDATA: INFO: ---- 00008: BC_BIOMASS
EXTDATA: INFO: ---- 00009: BC_SHIP
EXTDATA: INFO: ---- 00010: BRC_AIRCRAFT
EXTDATA: INFO: ---- 00011: BRC_ANTEBRC1
EXTDATA: INFO: ---- 00012: BRC_ANTEBRC2
EXTDATA: INFO: ---- 00013: BRC_AVIATION_CDS
EXTDATA: INFO: ---- 00014: BRC_AVIATION_CRS
EXTDATA: INFO: ---- 00015: BRC_AVIATION_LTO
EXTDATA: INFO: ---- 00016: BRC_BIOFUEL
EXTDATA: INFO: ---- 00017: BRC_BIOMASS
EXTDATA: INFO: ---- 00018: BRC_SHIP
EXTDATA: INFO: ---- 00019: BRC_TERPENE
```

To get the GCM component spec, run with `PRINTSPEC: 1` in the `CAP.rc` and copy lines out that look like this:
```
#IMPORT spec for GCM
#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE
GENERIC: INFO: GCM, WSUB_CLIM, stdev in vertical velocity, m s-1, 3, esmf_field
GENERIC: INFO: GCM, MEGAN_ORVC, MEGAN_ORVC, kgC/m2/s, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_CROP, CLM4_PFT_CROP, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_C4_GRSS, CLM4_PFT_C4_GRSS, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_C3_NARC_GRSS, CLM4_PFT_C3_NARC_GRSS, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_C3_ARCT_GRSS, CLM4_PFT_C3_ARCT_GRSS, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_DECD_BORL_SHRB, CLM4_PFT_BDLF_DECD_BORL_SHRB, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_DECD_TMPT_SHRB, CLM4_PFT_BDLF_DECD_TMPT_SHRB, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_EVGN_SHRB, CLM4_PFT_BDLF_EVGN_SHRB, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_DECD_BORL_TREE, CLM4_PFT_BDLF_DECD_BORL_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_DECD_TMPT_TREE, CLM4_PFT_BDLF_DECD_TMPT_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_DECD_TROP_TREE, CLM4_PFT_BDLF_DECD_TROP_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_EVGN_TMPT_TREE, CLM4_PFT_BDLF_EVGN_TMPT_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_BDLF_EVGN_TROP_TREE, CLM4_PFT_BDLF_EVGN_TROP_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_NDLF_DECD_BORL_TREE, CLM4_PFT_NDLF_DECD_BORL_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_NDLF_EVGN_BORL_TREE, CLM4_PFT_NDLF_EVGN_BORL_TREE, 1, 2, esmf_field
GENERIC: INFO: GCM, CLM4_PFT_NDLF_EVGN_TMPT_TREE, CLM4_PFT_NDLF_EVGN_TMPT_TREE, 1, 2, esmf_field
```

Finally just grab the right yaml files for ExtData.

To run you will of course need to do some further editing of the produced files and link in the acutal data using the same convention `gcm_run.j` does.
167 changes: 167 additions & 0 deletions Tests/generate_extdatadriver_input.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#!/usr/bin/env python3
from yaml import load,dump
import argparse
import os
import yaml
import glob

dims_dict = {"2":"xy", "3":"xyz"}

def get_dims(component_map, name):
for comp in component_map:
if name in component_map[comp]:
dims = component_map[comp][name]["dims"]
return dims

def get_vars_needed(input_file):

output_list = []
f = open(input_file,"r")
lines = f.readlines()
f.close()
for line in lines:
temp = line.split()
output_list.append(temp[4])

return output_list

def get_extdata_map(input_dir):

input_files = glob.glob(input_dir+"/*.yaml")
export_list = {}
for input_file in input_files:
f = open(input_file,'r')
extdata_def = yaml.safe_load(f)
f.close()
for short_name in extdata_def["Exports"]:
export_list.update({short_name:extdata_def["Exports"][short_name]})
return export_list

def get_block(cvs_file):

temp = cvs_file[0].split(' ')
state_type = temp[1][1:].strip()
component = temp[4].strip()
i=2
for line in cvs_file[2:]:
if "spec for" in line:
break
i=i+1
return component,state_type,i


def get_component_map(cvs_file):

i_start = 0
i_end = 0
n_lines = len(cvs_file)
components = {}
while i_start < n_lines-1:

comp_name,state_type,i_end = get_block(cvs_file[i_start:])
comp_map = {}
for i in range(i_end-2):
line = cvs_file[i_start+2+i]
values = line.split(',')
short_name = values[1].strip()
long_name = values[2].strip()
units = values[3].strip()
dims = values[4].strip()
item_type = values[5].strip()
comp_map.update({short_name:{"long_name":long_name,"units":units,"item_type":item_type,"dims":dims}})
components.update({comp_name+"_"+state_type:comp_map})
i_start = i_start + i_end

return components

def parse_args():
p = argparse.ArgumentParser(description='Generarte input files for ExtDataDriver to simulate GEOS')
p.add_argument('extdata_provided',type=str,help='a list of items ExtData should fill',default=None)
p.add_argument('spec_def',type=str,help='the GEOS gcm import state from the printspec',default=None)
p.add_argument('extdata_dir',type=str,help='diretory with all the yaml imputs for extdata',default=None)
p.add_argument('-e','--export',action='store_true',help='also include exports for corresponding imports')

return vars(p.parse_args())

if __name__ == '__main__':

args = parse_args()

extdata_list = args['extdata_provided']
do_exports = args['export']
input_file = args['spec_def']
f = open(input_file,"r")
input_rc = f.readlines()
f.close()

extdata_directory = args['extdata_dir']
extdata_def = get_extdata_map(extdata_directory)

f_agcm = open("AGCM.rc",'w')
# component
component_map = {}
component_map = get_component_map(input_rc)

vars_needed = get_vars_needed(extdata_list)

nl = "\n"
cm = " , "

# Import state
written = []
f_agcm.write("IMPORT_STATE::"+nl)

for item in vars_needed:
if item in extdata_def:
long_name = "NA"
units = "NA"
dims = get_dims(component_map, item)
cdims = dims_dict[dims]

if item not in written:
f_agcm.write(item+cm+long_name+cm+units+cm+cdims+cm+"c"+nl)
written.append(item)

f_agcm.write("::"+nl)

# Export state
if do_exports:
written = []
f_agcm.write("EXPORT_STATE::"+nl)
for item in vars_needed:
if item in extdata_def:
long_name = "NA"
units = "NA"
dims = get_dims(component_map, item)
cdims = dims_dict[dims]

if item not in written:
f_agcm.write(item+cm+long_name+cm+units+cm+cdims+cm+"c"+nl)
written.append(item)

f_agcm.write("::"+nl)

f_hist = open("HISTORY.rc",'w')
f_hist.write("GRID_LABELS:"+nl)
f_hist.write("::"+nl)
f_hist.write("COLLECTIONS: my_collection"+nl)
f_hist.write("::"+nl)
f_hist.write("my_collection.template: 'nc4'"+nl)
f_hist.write("my_collection.format: 'CFIO'"+nl)
f_hist.write("my_collection.frequency: '240000'"+nl)
first = True
written = []
for item in vars_needed:
if item in extdata_def:
if item not in written:
if first:
first = False
f_hist.write("my_collection.fields:'"+item+"' , 'Root',"+"\n")
else:
f_hist.write("'"+item+"' , 'Root',"+"\n")
written.append(item)
f_hist.write("::")

f_hist.close()
f_agcm.close()

12 changes: 9 additions & 3 deletions base/MAPL_EsmfRegridder.F90
Original file line number Diff line number Diff line change
Expand Up @@ -1431,13 +1431,13 @@ subroutine create_route_handle(this, kind, rc)
real(real64), pointer :: src_dummy_r8(:,:), dst_dummy_r8(:,:)
type (ESMF_Field) :: src_field, dst_field

integer :: srcTermProcessing
integer :: srcTermProcessing, num_mask_values
integer, pointer :: factorIndexList(:,:)
integer, allocatable :: dstMaskValues(:)
real(ESMF_KIND_R8), pointer :: factorList(:)
type(ESMF_RouteHandle) :: dummy_rh
type(ESMF_UnmappedAction_Flag) :: unmappedaction
logical :: global, isPresent, has_mask
logical :: global, isPresent, has_mask, has_dstMaskValues
type(RegridderSpecRouteHandleMap), pointer :: route_handles, transpose_route_handles
type(ESMF_RouteHandle) :: route_handle, transpose_route_handle
character(len=ESMF_MAXPATHLEN) :: rh_file,rh_trans_file
Expand Down Expand Up @@ -1512,6 +1512,13 @@ subroutine create_route_handle(this, kind, rc)
end if
call ESMF_GridGetItem(spec%grid_out,itemflag=ESMF_GRIDITEM_MASK, &
staggerloc=ESMF_STAGGERLOC_CENTER, isPresent = has_mask, _RC)
call ESMF_AttributeGet(spec%grid_out, name=MAPL_DESTINATIONMASK, isPresent=has_dstMaskValues, _RC)
if (has_dstMaskValues) then
_ASSERT(has_mask, "masking destination values when no masks is present")
call ESMF_AttributeGet(spec%grid_out, name=MAPL_DESTINATIONMASK, itemcount=num_mask_values, _RC)
allocate(dstMaskValues(num_mask_values), _STAT)
call ESMF_AttributeGet(spec%grid_out, name=MAPL_DESTINATIONMASK, valuelist=dstMaskValues, _RC)
end if

counter = counter + 1

Expand All @@ -1521,7 +1528,6 @@ subroutine create_route_handle(this, kind, rc)
call ESMF_AttributeGet(spec%grid_in, name='Global',value=global,rc=status)
if (.not.global) unmappedaction=ESMF_UNMAPPEDACTION_IGNORE
end if
if (has_mask) dstMaskValues = [MAPL_MASK_OUT] ! otherwise unallocated
select case (spec%regrid_method)
case (REGRID_METHOD_BILINEAR, REGRID_METHOD_BILINEAR_MONOTONIC)

Expand Down
3 changes: 3 additions & 0 deletions base/MAPL_XYGridFactory.F90
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,9 @@ subroutine add_mask(this,grid,rc)
mask = MAPL_MASK_IN
where(fptr==MAPL_UNDEF) mask = MAPL_MASK_OUT

call ESMF_AttributeSet(grid, name=MAPL_DESTINATIONMASK, &
itemCount=1, valueList=[MAPL_MASK_OUT], _RC)

_RETURN(_SUCCESS)
end subroutine add_mask

Expand Down
4 changes: 4 additions & 0 deletions gridcomps/History/MAPL_HistoryCollection.F90
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ module MAPL_HistoryCollectionMod
integer :: acc_offset
integer :: ref_date
integer :: ref_time
integer :: start_date
integer :: start_time
integer :: end_date
integer :: end_time
integer :: duration
type(ESMF_Alarm) :: his_alarm ! when to write file
type(ESMF_Alarm) :: seg_alarm ! segment alarm controls when to write to new file
type(ESMF_Alarm) :: mon_alarm
type(ESMF_Alarm) :: start_alarm
type(ESMF_Alarm) :: end_alarm
integer,pointer :: expSTATE (:)
integer :: unit
Expand All @@ -70,6 +73,7 @@ module MAPL_HistoryCollectionMod
integer :: verbose
integer :: xyoffset
logical :: disabled
logical :: skipWriting
logical :: subVm
logical :: backwards ! Adds support for clock running in reverse direction
logical :: useNewFormat
Expand Down
Loading

0 comments on commit f51b43a

Please sign in to comment.