Read in ak, bk coefficients #36
Conversation
|
Hi @mlee03 . Glad that you could clean up the predefined vertical levels, which is getting to be a real mess. I agree that the best place for creating the vertical levels is in the preprocessor. One concern (not related to this commit) is that there is no foolproof way to automatically generate a good set of ak/bk levels, and when creating an entirely novel set of levels some degree of hand-tuning is necessary to avoid stability problems. Xi Chen had developed a tool which can help, and interpolating from predefined level sets is usually pretty good, but some user discretion is needed when making new level sets. NB: In the future when I have broader comments like this, is there somewhere more appropriate to bring them up than in the comments of a semi-related PR? (Adding @bensonr @oelbert for their opinion.) Thanks. |
|
@lharris4: There's no way to auto-generate stable levels, but is there a way to check that they are unstable? We could eventually code that in. |
|
@FlorianDeconinck there is no a priori way to ensure stability but typically we can examine the differences in delp and delz in a variety of situations, which is what Xi's tool does. We could run tests to ensure that the differences do not exceed some tolerance. This might be a good way forward; furthermore smoothing can be applied to improve the smoothness and stability of the selected coordinate. |
|
Logged for posterity: #38 On the other topic, though obviously I am but a stranger here, I shall remind that there's a "Discussion" system on Github, which is a wiki-liky structure and could accommodate ongoing discussions and/or thinking on feature sets. |
|
@FlorianDeconinck thanks for logging that. Also the discussions could potentially be a great resource. There are a precious few discussions on the FV3 repo and I would like to see this functionality used more. |
oelbert
left a comment
There was a problem hiding this comment.
This is a good start but there are a few things still do do. I think we talked about moving from .txt to .netcdf format for the pressure coefficient files, but also it would be good to have the yaml config file set the location of the ak and bk input file, and then the driver can pass that location as necessary during initialization. That way we also don't need so many copies of the files in the repo as well.
| km = 79 | ||
| eta_file = "./input/eta79.txt" | ||
| ak_79, bk_79 = np.loadtxt(eta_file, unpack=True) |
There was a problem hiding this comment.
I think this could go inside of test_set_hybrid_pressure_coefficients_correct
| pressure_data = set_hybrid_pressure_coefficients(km=90) | ||
|
|
||
|
|
||
| def test_set_hybrid_pressure_coefficients_correct(): |
There was a problem hiding this comment.
It might be worthwhile to parameterize this over the 79 and 91 k-level versions
| raise ValueError("Unexpected ks value") | ||
|
|
||
| if ptop != pressure_data.ptop: | ||
| raise ValueError("Unexpected ptopt value") |
There was a problem hiding this comment.
| raise ValueError("Unexpected ptopt value") | |
| raise ValueError("Unexpected ptop value") |
| pressure_data = set_hybrid_pressure_coefficients(km) | ||
|
|
||
| if not np.array_equal(ak_79, pressure_data.ak): | ||
| raise ValueError("Unexpected values in ak array") |
There was a problem hiding this comment.
| raise ValueError("Unexpected values in ak array") | |
| raise ValueError("ak values do not match input file") |
| raise ValueError("Unexpected values in ak array") | ||
|
|
||
| if not np.array_equal(bk_79, pressure_data.bk): | ||
| raise ValueError("Unexpected values in bk array") |
There was a problem hiding this comment.
| raise ValueError("Unexpected values in bk array") | |
| raise ValueError("bk values do not match input file") |
| eta_0 = 0.252 | ||
| surface_pressure = 1.0e5 # units of (Pa), from Table VI of DCMIP2016 |
There was a problem hiding this comment.
Since eta_0 is only used in vertical_coordinate maybe it should live there? I'm also starting to think that surface_pressure belongs in the util.constants at this point, could we move it there?
| """ | ||
| eta = 0.5 * ((ak[:-1] + ak[1:]) / surface_pressure + bk[:-1] + bk[1:]) | ||
| eta_v = vertical_coordinate(eta) | ||
| return eta, eta_v |
There was a problem hiding this comment.
Could these functions live in eta.py?
| ] | ||
| ) | ||
| # set path where the eta file lives | ||
| GRID_DIR = os.path.join(os.path.abspath("./"), "input/") |
There was a problem hiding this comment.
Instead of hardcoding the ak and bk files to path/input/etaX.txt we should pass the location of the file through the yaml config, similar to how Frank is setting up the model to read grid files. I'm happy to chat with you about how to do this
There was a problem hiding this comment.
Mi Kyung and I have been discussing this and plan to come up with a good location to place all necessary testing/example files.
There was a problem hiding this comment.
In order to reduce the need for multiple versions of the same data, could the test refer to the file in input/?
There was a problem hiding this comment.
Same comment as for tests/main/driver/input/eta79.txt
There was a problem hiding this comment.
Same comment as for tests/main/driver/input/eta79.txt
|
@mlee03 - can you or one of the other reviewers discuss the necessity of the empty init.py file in the tests/main/grid/ directory |
|
@bensonr, good point, to my limited understanding, I don't think it's needed here since we're not creating a package and the test is not being referenced by any modules. I think I created it here because there was one is the tests/main/driver directory 😁 😁 😁 but I will remove it |
|
@mlee03 - is there a procedure for creating the ak/bk netcdf files and is it documented anywhere? |
|
I took the ak/bk coefficients from what was coded in the original version of the eta module and created a python script to generate the netcdf files. I can document how to use the python netcdf module or the xarray module to create these files. Where should it be documented? |
|
Or a Jupyter notebook? |
oelbert
left a comment
There was a problem hiding this comment.
Looks good for the most part, but I still think the MetricTerms class should be dealing with any external files in the init method and not during potential runtime calls, so I've added some suggestions to the grid generation file.
| metric_terms = pace.util.grid.MetricTerms( | ||
| quantity_factory=quantity_factory, communicator=self.communicator | ||
| ) | ||
| metric_terms._eta_file = namelist["grid_config"]["config"]["eta_file"] | ||
|
|
There was a problem hiding this comment.
Shouldn't the eta file go in the metric terms init?
| self._dy_const = dy_const | ||
| self._deglat = deglat | ||
| self._halo = N_HALO_DEFAULT | ||
| self._eta_file = eta_file |
There was a problem hiding this comment.
The way this is currently structured it can cause reading the eta file at runtime, which I really want to avoid. I think a better way to do it is to set the private variables in the init method and just return them as cached properties:
| self._eta_file = eta_file | |
| ( | |
| self._ks, | |
| self._ptop, | |
| self._ak, | |
| self._bk, | |
| ) = self._set_hybrid_pressure_coefficients(eta_file) |
| if not self._eta_file == "None": | ||
| ( | ||
| self._ks, | ||
| self._ptop, | ||
| self._ak, | ||
| self._bk, | ||
| ) = self._set_hybrid_pressure_coefficients() | ||
| else: | ||
| raise ValueError("eta file is not specified") |
There was a problem hiding this comment.
| if not self._eta_file == "None": | |
| ( | |
| self._ks, | |
| self._ptop, | |
| self._ak, | |
| self._bk, | |
| ) = self._set_hybrid_pressure_coefficients() | |
| else: | |
| raise ValueError("eta file is not specified") |
| @@ -587,12 +589,15 @@ def ks(self) -> util.Quantity: | |||
| number of levels where the vertical coordinate is purely pressure-based | |||
| """ | |||
| if self._ks is None: | |||
There was a problem hiding this comment.
| if self._ks is None: |
| @@ -602,12 +607,15 @@ def ak(self) -> util.Quantity: | |||
| pk = ak + (bk * ps) | |||
| """ | |||
| if self._ak is None: | |||
There was a problem hiding this comment.
| if self._ak is None: |
| @@ -631,12 +642,15 @@ def ptop(self) -> util.Quantity: | |||
| the pressure of the top of atmosphere level | |||
| """ | |||
| if self._ptop is None: | |||
There was a problem hiding this comment.
| if self._ptop is None: |
| if not self._eta_file == "None": | ||
| ( | ||
| self._ks, | ||
| self._ptop, | ||
| self._ak, | ||
| self._bk, | ||
| ) = self._set_hybrid_pressure_coefficients() | ||
| else: | ||
| raise ValueError("eta file is not specified") |
There was a problem hiding this comment.
| if not self._eta_file == "None": | |
| ( | |
| self._ks, | |
| self._ptop, | |
| self._ak, | |
| self._bk, | |
| ) = self._set_hybrid_pressure_coefficients() | |
| else: | |
| raise ValueError("eta file is not specified") |
| ) | ||
| pressure_coefficients = set_hybrid_pressure_coefficients(self._npz) | ||
| pressure_coefficients = eta.set_hybrid_pressure_coefficients( | ||
| self._npz, self._eta_file |
There was a problem hiding this comment.
| self._npz, self._eta_file | |
| self._npz, eta_file |
plus adding eta_file as an explicit argument
There was a problem hiding this comment.
I don't know if this needs to be a notebook but I don't think it has to not be a notebook ¯_(ツ)_/¯
There was a problem hiding this comment.
Same as the other notebook ¯_(ツ)_/¯
* Benchmark changes * Added benchmark configurations * Removed benchmark configs from configs to be tested in unit tests * Changed dace submodule to point to Florian fix * Dace submodule points to gcc_dies_on_dacecpu branch * Set 'rf_fast' to true in baroclinic_c384_cpu/gpu.yaml * fix mpi4py version (#51) * [Feature] Better translate test (#39) (#47) Translate test: small improvements - Parametrize perturbation upon failure - Refactor error folder to be `pwd` based - Fix GPU translate unable to dump error `nc` - Fix mixmatch precision on translate test - Update README.md Test fix: - Orchestrate YPPM for translate purposes Misc: - Fix bad logger formatting on DaCeProgress * [NASA] [Feature] Guarding against unimplemented configuration (#40) (#48) * [Feature] Guarding against unimplemented configuration (#40) Guarding against unimplemented namelists options: - a2b_ord4 - d_sw - fv_dynamics - fv_subgridz - neg_adj3 - divergence damping - xppm - yppm Misc: - Fix `netcdf_monitor` not mkdir the directory - Add `as_dict` to the dycore state to dump the dycore more easily * Unused assert * Update fv3core/pace/fv3core/stencils/yppm.py Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> * Update fv3core/pace/fv3core/stencils/xppm.py Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> * Change NotImplemented to ValueError for n_sponge<3 * lint --------- Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> * Re-try of updating dace submodule to track Florian fix branch * Reverted gt4py submodule to match main checkout * Added benchmark README file * Read in ak, bk coefficients (#36) * initial changes to read in ak bk * read ak/bk * add xfail * remove input dir * further changes to unit tests * finish up test * add history * commit uncommited files * fix test comment * add input to top * read in data * read in netcdf file in eta mod * remove txt file * test * modify test and fix generate.py * remove emacs backup file * driver tests pass * fix helper.py * fix fv3core tests * fix physics test * fix grid tests * nullcommconfig * cleanup input * remove driver input * remove top level input * fix circular import problems * modify eta_file readin for test_restart_serial * comment out 91 test * rm safety checks * revert diagnostics.py * restore driver.py * revert initialization.py * restore state.py * restore analytic_init.py * restore init_utils.py and analytic_init.py * restore c_sw.py * d2a2c_vect.py * restore fv3core/stensils * restore translate_fvdynamics * restore physics/stencils * restore stencils * remove circular dependency * use pytest parametrize * cleanup generation.py * fstrinngs * add eta_file to MetricTerm init * remove eta_file argument in new_from_metric_terms and geos_wrapper * use pytest parametrize for the xfail tests * use pytest parametrize for the xfail tests * fix geos_wrapper and grid * fix tests * fstring * add test comments * fix util/HISTORY.md * fix comments * remove __init__.py from tests/main/grid * add jupyter notebooks to generate eta files * generate ak,bk,ptop on metricterm init * fix tests * exploit np.all in eta mod * remove tests/main/grid/input * update ci * test * remove input * edit ci yaml * remove push --------- Co-authored-by: mlee03 <Mikyung.Lee@lscamd50-d.gfdl.noaa.gov> * Move Active Physics Schemes to Config (#44) * initial commit, need to adapt and run tests * revising scheme name * tests pass * update history * linting * changing typehints for physics schemes to enum instead of str * driver now works with physics config enum, tests pass * fixed tests * missed one * D-grid data input method (#42) * Testing changes reflected across branches * Undoing changes made in build_gaea_c5.sh * Testing vscode functionality, by adding a change to external_grid branch * Testing vscode functionality, by adding a change to external_grid branch * Addition of from_generated method and calc_flag to util/pace/util/grid/generation.py * Added get_grid method for external grid data to driver/pace/driver/grid.py * Preliminary xarray netcdf read in method added to driver/pace/driver/grid.py * Updating util/pace/util/grid/generation.py from_generated method * Addition of external grid data read in methods for initialization of grid. Current method uses xarray to interact with netcdf tile files. Values for longitutde, latitude, number of points in x an y, grid edge distances read in. * driver/examples/configs/test_external_C12_1x1.yaml * Preliminary unit test for external grid data read in * Current state of unit tests as of 27 Nov 2023 * External grid method and unit tests added * Re-excluding external grid data yamls from test_example_configs.py * Update driver/pace/driver/grid.py Co-authored-by: Florian Deconinck <deconinck.florian@gmail.com> * Changed name of grid initializer function to match NetCDF dependency and class descriptor * Update util/pace/util/grid/generation.py Moved position of doc string for "from_external" MetricTerms class method Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> * Fixed indentation error in generation.py from suggestion in PR 42 * Removal of TODO comment in grid.py, changes to method of file accessing in test_analytic_init, test_external_grid_* * Changed grid data read-in unit tests to compare data directly from file to driver grid data generated from yaml * Change to reading in lon and lat, other metric terms calculated as needed * Removed read-in of dx, dy, and area. Changed unit tests to compare calculated area to 'ideal' surface area as given by selected constants type. * Update tests/mpi_54rank/test_external_grid_1x1.py Incorrect name of test in test_external_grid_1x1.py changed to match file name Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> * Added comparisons for read-in vs generated by driver lon, lat, dx, dy, and area data to unit tests * Added relative error calculations to unit tests for external grid data read-in * External grid data read in tests changed: relative errors printed by each rank and get_tile_number replacing get_tile_index * Removing commented out sections in test_external_grid_2x2.py Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> * Updated external grid data read-in to take configuration and input data locations from command line, updated test description, and added documentation on grid construction to external grid data configuration selection dataclass. * Updated documentation in grid.py * Updated external grid data read in unit test to use parametrize functionality of pytest * Ammended files to reference changes to PR 36 --------- Co-authored-by: Frank Malatino <Frank.Malatino@ldt-4788481.gfdl.noaa.gov> Co-authored-by: Florian Deconinck <deconinck.florian@gmail.com> Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> --------- Co-authored-by: Oliver Elbert <Oliver.Elbert@noaa.gov> Co-authored-by: Florian Deconinck <deconinck.florian@gmail.com> Co-authored-by: Oliver Elbert <oliver.elbert36@gmail.com> Co-authored-by: MiKyung Lee <58964324+mlee03@users.noreply.github.com> Co-authored-by: mlee03 <Mikyung.Lee@lscamd50-d.gfdl.noaa.gov> Co-authored-by: Frank Malatino <Frank.Malatino@ldt-4788481.gfdl.noaa.gov>
Purpose
The
akandbkcoefficients required to compute the pressure levels are hard-coded in theetamodule forkm=71,km=72,km=91, andkm=139number of vertical levels. This limits the number of vertical levels a user can choose to run models. By allowing the users to provide theakandbkvalues in a simple ASCII file, the users have the freedom to specify any number of vertical levels.Code changes:
In this PR,
The hard-coded
akandbkarray values have been removed. Instead, these values are read in, for example, from theinput/eta79.txtfile where the input directory is expected to reside in the directory of the main program and 79 represents the value ofkm. Checks were put in place to ensure thatakandbkarrays are equal to the specified value ofkmetaandeta_vare monotonically increasingExisting unit tests have been modified to read in the coefficients from an
etafile and new unit tests were created to test the modifiedetamodule. These tests were modified under the assumption that in the future, all input files will reside in one main input directory where the input directory resides in the directory of the main program. This assumption required creating input directories to all the possible testing directories intests.Lastly, the functions
vertical_coordinateandcompute_eta, originally located in thebaroclinic_jablonowski_williamsonmodule have been moved to a newly createdutilmodule in the pace/util/grid directory. This change was made because it seemed more fitting for the abovementioned functions to reside with other grid-related functions.Requirements changes:
inputdirectory with eta files named aseta##.txtwhere ## refers to the value ofkmChecklist
Before submitting this PR, please make sure:
pace-util, HISTORY has been updatedAdditionally, if this PR contains code authored by new contributors: