Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diagnostics Downsampling by a factor 2 for MOM6 #869

Merged

Conversation

nikizadehgfdl
Copy link
Contributor

@adcroft @Hallberg-NOAA @StephenGriffies This pull request is solely to ease the review process. Please review the code change (mainly one file), particularly please review the main algorithm starting at line 3644 of MOM_diag_mediator.F90 !

This code update brings in a preliminary capability for diagnostics decimation. Current limitations are (but may not be limited to)

  1. Commensurate layouts only. The layout should be chosen smartly so that the coarsened cells do not cross the processor boundary, i.e., NIGLOBAL/layout_x and NJGLOBAL/layout_y should both be divisible by the decimation level dl (if such diagnostics is present in diag_table). It's hard to lift this limitation, and it may not be desirable due to halo updates slowing down the model and beating the purpose of this project.

  2. Only dl=2 support is coded. It is easy to extend this to include dl=4, but for a general dl we need to design an array of grids so that we have access to e.g., G(dl=6)%isc, etc

Good news is that this update seems to be working, reducing the size of history files significantly and without an obvious performance hit.
You can preview and explore some of results via this notebook:
https://github.com/nikizadehgfdl/grid_generation/blob/master/jupynotebooks/DiagnosticsDataDecimation.ipynb

- To produce the full diagnostics for 1/8 degree model
  it is needed to reduce the size of output files.
  This could be done by "averaging" over a few neighboring grid cells
  and output the resulting fields on the reduced domain.
  That's what we call decimation and is the purpose of this project branch.
- Prototype zaps all diagnostics by a factor of 2
- Works only for the native grid diagnostics
- _z diagnostics complain about the local mask array index
- Next: make diag decimation optional at diag_table level
- This update allows the use to request a level 2 decimated diagnostics
  in the diag_table as following example shows

OMp5
1900 1 1 0 0 0
"ocean_hour",            0, "days",   1, "days", "time"
"ocean_model",   "tos",          "tos",              "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "thetao",       "thetao",           "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "umo",          "umo",              "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "vmo",          "vmo",              "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "volcello",     "volcello",         "ocean_hour",         "all", "mean", "none",2 # Cell measure for 3d data
"ocean_hour_d2",            0, "days",   1, "days", "time"
"ocean_model_d2",   "tos",          "tos",              "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "thetao",       "thetao",           "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "umo",          "umo",              "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "vmo",          "vmo",              "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "volcello",     "volcello",         "ocean_hour_d2",         "all", "mean", "none",2 # Cell measure for 3d data

- At the moment it works only for "Native" grid diagnostics and level 2 decimation (bination?)
- It has to be extended to non-native diagnostics, e.g.,
"ocean_model_z_d2",   "tos",          "tos",              "ocean_hour_z_d2",         "all", "mean", "none",2

- It has to be extended to arbitrary level of decimation, e.g.,
"ocean_model_z_d4",   "tos",          "tos",              "ocean_hour_z_d4",         "all", "mean", "none",2
"ocean_model_z_d2",   "tos",          "tos",              "ocean_hour_z_d2",         "all", "mean", "none",2

- Also, note that this prototype only works for smart choices of layouts where "combined" cells are on the same pe
  We need a major design revision to extend this to arbitrary layouts that would need halo updates and halo handling.
- This update allows using non-native and decimated diagnostics
  as well as their combinations. E.g., it works for a diag_table as shown below.
- I have to
      validate with a full diagnostics
      validate individual diagnostics make sense
      study the memory foot print to make sure the decimate rotuines have no leak (due to extensive use of fortran pointers)
- Also we have to work on an averaging rather than sub-sampling of the fields as is done in this prototype

OM5p5
1900 1 1 0 0 0
"ocean_hour",            0, "days",   1, "days", "time"
"ocean_model",   "tos",          "tos",              "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "thetao",       "thetao",           "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "umo",          "umo",              "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "vmo",          "vmo",              "ocean_hour",         "all", "mean", "none",2
"ocean_model",   "volcello",     "volcello",         "ocean_hour",         "all", "mean", "none",2 # Cell measure for 3d data
"ocean_hour_d2",            0, "days",   1, "days", "time"
"ocean_model_d2",   "tos",          "tos",              "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "thetao",       "thetao",           "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "umo",          "umo",              "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "vmo",          "vmo",              "ocean_hour_d2",         "all", "mean", "none",2
"ocean_model_d2",   "volcello",     "volcello",         "ocean_hour_d2",         "all", "mean", "none",2 # Cell measure for 3d data
"ocean_hour_z",            0, "days",   1, "days", "time"
"ocean_model_z",   "thetao",       "thetao",          "ocean_hour_z",         "all", "mean", "none",2
"ocean_model_z",   "umo",          "umo",             "ocean_hour_z",         "all", "mean", "none",2
"ocean_model_z",   "vmo",          "vmo",             "ocean_hour_z",         "all", "mean", "none",2
"ocean_model_z",   "volcello",     "volcello",        "ocean_hour_z",         "all", "mean", "none",2 # Cell measure for 3d data
"ocean_hour_z_d2",            0, "days",   1, "days", "time"
"ocean_model_z_d2",   "thetao",       "thetao",          "ocean_hour_z_d2",         "all", "mean", "none",2
"ocean_model_z_d2",   "umo",          "umo",             "ocean_hour_z_d2",         "all", "mean", "none",2
"ocean_model_z_d2",   "vmo",          "vmo",             "ocean_hour_z_d2",         "all", "mean", "none",2
"ocean_model_z_d2",   "volcello",     "volcello",        "ocean_hour_z_d2",         "all", "mean", "none",2 # Cell measure for 3d data
- The design of decimating subroutines with pointer manipulations was bad
  and causing memory leak. Using "allocatable" arrays instead is not
  as elegant but avoids memory leaks at the cost of bringing a few lines
  of code fo allocating temporary arrays outside the decimating subroutines.
  The FORTRAN garbage collection takes care of deallocating the "allocatable"s
  when their scope ends (unlike pointers).
- This update introduces aggregation methods, so that we can point average
  the fields rather than subsampling. This cab be extended to fancier methods
  such as area or volume averaging
- The masks for non-native decimated diags were not set right
- Some cleanup of the code to consolidate new calls
- Note that locmask => NULL() shoulbe in the body of subroutines
  not in the definition section. If it is in the definition section
  it is set to null only on the first entry (it is automatically "save"ed)
  and on subsequent entry it is whatever it was the last time.
- All decimated axes need to have the non-decimated mask3d fields initialized correctly.
  The non-decimated masks are being used in the decimation algorithm for the diagnostics fields
- According to Alistair, the decimation method could be solely deduced
  from the axes%x_cell_method, axes%y_cell_method and probably the area_cell_method
  at the time of send_data
- This is the summary of the algoritm
  f(Id,Jd) = \sum_{i,j} f(Id+i,Jd+j) * weight(Id+i,Jd+j) / [ \sum_{i,j} weight(Id+i,Jd+j)]
     Id,Jd are the decimated (coarse grid) indices run over the coarsened compute grid,
     i and j run from 0 to dl-1 (dl being the decimation level)
     if and jf
     weight(if,jf) run over the original fine computre grid

     x_cell_method  y_cell_method  area_cell_method    weight(if,jf)        example
--------------------------------------------------------------------- -------------
     mean           mean           mean                A(if,jf)*h(if,jf)      theta
     point          mean           mean                dy(if,jf)*h(if,jf)     u
     mean           point          mean                dx(if,jf)*h(if,jf)     v
     mean           mean           sum                 A(if,jf)               h*theta
     sum            sum            sum                 1                      volcello
     point          sum            sum                 1                      umo
- This commit extends the proposed decimatipn algorithm to cover
  all the present diagnostics in the OM4_025 diag_table
  There may be more cases that need to be coded up later
- Beware! Currently only commensurate layouts are supported. I.e.,
  the decimated subgrid cells should all be contained in the same core (pe).
  For this to happend the layout of the model runs should be chosen
  so that NIGLOBAL/layout_x and NJGLOBAL/layout_y are both divisible by dl
  (decimation level) if a _dl diagnostics is present in the diag_table
- This is a major limitition of the current implementation. But the extension
  to arbitrary layouts would required cross processor communications (halo updates)
  which may slow down the model considerably and beat the purpose of decimation.
@ashao
Copy link
Collaborator

ashao commented Oct 25, 2018

Thanks @nikizadehgfdl for implementing this an exciting new capability.

I'll try to look at this a little more carefully later, but here are some of my initial comments based on a brief scan of the code. (I'll also include these at the appropriate points in th PR as comments)

  1. It looks like the specification of method could be replaced using because the information in the x,y,v cell methods is sufficient to determine which 'method' of decimation/aggregation.
  2. There still is the problem of continental boundaries, to which I have no good solution.
  3. Reduce the amount of duplicated code and aid future development by putting the calculation of the decimated grid value into a function. Maybe decimate_field_3d could also use decimate_field_2d?

@balaji-gfdl
Copy link

Can I just state for the record that decimation specifically means removal of a tenth? (ie *0.9)? It comes from a form of punishment in Roman armies, where they would randomly kill one out of every 10 soldiers.

I am (quite seriously) suggesting we use an accurate technical term, rather than an inaccurate metaphorical term: the correct term for what we are doing is "downsampling", which is precise and unambiguous.

Copy link
Collaborator

@adcroft adcroft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does zap2 abbreviate?

@@ -1566,6 +1569,28 @@ subroutine MOM_domains_init(MOM_dom, param_file, symmetric, static_memory, &
endif
endif

global_indices(1) = 1 ; global_indices(2) = int(MOM_dom%niglobal/2)
global_indices(3) = 1 ; global_indices(4) = int(MOM_dom%njglobal/2)
xhalo_zap2 = int(MOM_dom%nihalo/2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend a halo of 1 (or 0?) since we're not doing wide-stencil computations. It should not change anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this does not work. I have to choose the MOM_dom%nihalo/dl otherwise the checks for downsampled field size complain that it does not match the expected size of original_dszi/dl .

@@ -122,6 +142,25 @@ module MOM_diag_mediator
type(diag_grids_type), dimension(:), allocatable :: diag_grids !< Primarily empty, except h field
end type diag_grid_storage

!> integers to encode the total cell methods
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these enumerated integers used for 2d (xy) fields too, or do we need PP, PS, PM, SP, SS, SM, MP, MM, MS as well?

Copy link
Contributor Author

@nikizadehgfdl nikizadehgfdl Oct 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, 2d fields can use the same 3 digit code, although the v-code (3rd digit from left) might not be needed.
All 2d diagnostics in diag_table.MOM6 come with a "Point" for the v_cell_method, so I assume they are all either area averaged (MMP) or summed or sampled, in other words, no 2d field is volume averaged! Is that correct?
Although I coded the "MMM" for 2d fields I just found out it's never used and am going to delete that case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could I suggest that we do the enumeration using 1,2,3 instead of 0,1,2, so that the 2-d variant PS (which would currently resolve to 1) can not be confused with the 3-d PPS (which would also resolve to 1). With 1,2,3, PS becomes 12, whereas PPS becomes 112. 0 could be reserved for no-axis.

! Vertical axes for the interfaces and layers
call define_axes_group(diag_cs, (/ id_zi /), diag_cs%axesZi, &
call define_axes_group(diag_cs, (/ id_zi /), diag_cs%axesZi, nz=1, &
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is nz=1 doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably nothing. I'll remove it.

!! Id,Jd are the decimated (coarse grid) indices run over the coarsened compute grid,
!! if and jf are the original (fine grid) indices
!!
!!example x_cell y_cell v_cell algorithm_id impemented weight(if,jf)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume delta(i,j) in these comments refers to Kronecker delta...

!!---------------------------------------------------------------------------------------
!!theta mean mean mean MMM =222 G%areaT(if,jf)*h(if,jf)
!!u point mean mean PMM =022 dyCu(if,jf)*h(if,jf)*delta(if,Id)
!!? point sum mean PSM =012 dyCu(if,jf)*h(if,jf)*delta(if,Id) right?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
!!? point sum mean PSM =012 dyCu(if,jf)*h(if,jf)*delta(if,Id) right?
!!? point sum mean PSM =012 h(if,jf)*delta(if,Id)

@nikizadehgfdl nikizadehgfdl changed the title [WIP:] Please do not merge! For review! Diagnostics Decimation [WIP:] Please do not merge! For review! Diagnostics Downsampling Oct 26, 2018
- This update addresses and implements suggestions in the reviews
  by Alisair and Balaji, particularly
  - Rename the whole project and scheme to downsampling
  - Make a container type for the horizontal indices G%Hd2 for downsampling level 2
- Removed the trailing blanks caught by travis
- There was a unnecessary check for symmetric case
- This updates fixes the symetric memory case.
  By hook or by crook, the downsampled diagnostics now run for both
  symmetric and non-symmetric memory cases.
- Could I suggest that we do the enumeration using 1,2,3 instead of 0,1,2,
  so that the 2-d variant PS (which would currently resolve to 1) can not
  be confused with the 3-d PPS (which would also resolve to 1).
  With 1,2,3, PS becomes 12, whereas PPS becomes 112. 0 could be reserved for no-axis.

- There is still no need to have two digit codes, may be because
  there are no diagnostics with PP* in the full diag_table.MOM6
@nikizadehgfdl nikizadehgfdl changed the title [WIP:] Please do not merge! For review! Diagnostics Downsampling Diagnostics Downsampling by a factor 2 for MOM6 Nov 19, 2018
@nikizadehgfdl
Copy link
Contributor Author

I think this has been tested enough to go through a regular PR testing.

@adcroft
Copy link
Collaborator

adcroft commented Nov 19, 2018

@Hallberg-NOAA
Copy link
Collaborator

The latest version of this PR is being tested with https://gitlab.gfdl.noaa.gov/ogrp/MOM6/pipelines/7347.

@Hallberg-NOAA Hallberg-NOAA merged commit 00f634b into mom-ocean:dev/gfdl Mar 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants