Conversation
4ccb04f to
a3baa9c
Compare
|
Nice! All tests passing! |
| """ | ||
| super().__init__(mpas_core=mpas_core, name='mitgcm_baroclinic_gyre') | ||
|
|
||
| for resolution in ['80km']: |
There was a problem hiding this comment.
Consider adding a comment that resolutions here must be added with the 'km' suffix (since later you chop off the last 2 characters to get the float)
There was a problem hiding this comment.
An alternative would be to provide the resolution as a float and add the km suffix to the subdirectory. I think that might be cleaner. (I know we were following ziso, so that one should probably be fixed in a similar way.)
There was a problem hiding this comment.
By the way, I have something along these lines here, where the resolution is always given in meters
compass/compass/ocean/tests/turbulence_closure/default/__init__.py
Lines 38 to 41 in f8af494
There was a problem hiding this comment.
@cbegeman Working on this resolution change now. A few questions/suggestions:
- Are you satisfied with resolution in meters by default? It makes sense for turbulence closure since we go to fine resolution. Is it best to be consistent across cases? Happy to switch mine, just wanted to check.
- the comment blocks in your
forward(L12, L25) andinitial_state(L22, L34) still carry comments where resolution is expected to be string, though it is the float that is passed (as far as I understand). It may be good to propagate the update. - The
runinforwardstill assumes a string resolution with units. I couldn't find a call for it so maybe it's just stale code, but worth updating in case it ever get exercised.
There was a problem hiding this comment.
- If the
resolutionvariable is only present in your case-specific python code (e.g., not in the config file), I think you can use whatever units are convenient for your cases. We care more about standardizingdc(in config files) and the resolution directory name across cases. - Thanks for pointing this out. I'm not actively developing that branch (and case) any more because we didn't have success validating mpas_les. If I return to it, I'll fix this up.
- Same as (2)
| bottT = temperature[0, 200, -1].values | ||
| surfT = temperature[0, 200, 0].values | ||
| print(f'bottom T: {bottT} and surface : {surfT}') | ||
| salinity = 34.0 * xr.ones_like(temperature) |
There was a problem hiding this comment.
Consider making certain initial temperature and salinity parameters a part of the mitgcm_baroclinic_gyre section in your config file
There was a problem hiding this comment.
The initial temperature is a function of depth. @alicebarthel has constructed a function that's a pretty good approximation of the table of numbers used in the MITgcm version of the test case. It's full of "magic" numbers so they wouldn't be super easy to add to the config file. But maybe there would be a way to give the top (z=0) and bottom (z=bottom_depth) temperature and have them vary between those two with your prescribed functional form? That would seem cleaner to me.
I wouldn't hardcode sampling bottT and surfT at the 200th grid cell here. Either you should take grid cell 0 or you'll want to have a number somehow based on nCells. We don't necessarily know that the mesh will have a 200th grid cell (though it's obviously highly likely) since we're flexible about the resolution.
Regarding the initial salinity, I agree for sure that that needs to be a config option rather than a magic number here.
There was a problem hiding this comment.
Good point @xylar re. cell 200. @cbegeman I like the idea of it being more general (setting T in cfg) but I have not come up with a satisfying way to do that at this stage. For the original purpose of matching MITgcm, hard-coding the structure was easiest. It can extend to a deeper set-up, but approximates their values over 0-1800m. I'll look to see about setting it from top and bottom T keeping the existing functional form. We could do a prettier functional form with, say, a thermocline depth parameter setting the change in T=f(z) shape, but I have not looked into it that closely.
There was a problem hiding this comment.
@alicebarthel, couldn't you have config options that are the temperatures in the middle of the top and bottom layers respectively? Then, couldn't you take your existing functional form but stretch it linearly so it hits the desired top and bottom temperatures?
Alternatively, if you want to be very particular about having the same temperature profile independent of resolution, couldn't you do the same but instead of the middle of the top and bottom layers, you would use z = 0 and z=1800 m. The default values would be chosen such that the temperature in the middle of the top and bottom layers is quite close to the value you currently get with your functional form.
There was a problem hiding this comment.
Moved the constant salinity value to the cfg file. The initial temperature profile is now set (still with a "magical" functional form and a fitted parameter) from the top and bottom temperature set at the surface (z=0m) and bottom (z = bottom_depth). The default values approximate the mitgcm stratification, but we could add a table to reach to be more exact.
|
@alicebarthel I think this is coming together really nicely! I left only minor comments at this point. |
0c341eb to
3bac95a
Compare
4145dce to
b976f7a
Compare
85775b3 to
6a48d21
Compare
xylar
left a comment
There was a problem hiding this comment.
I had some issues mainly with the docs. A few things to clean up there.
|
I successfully ran the |
|
@alicebarthel, the outputs you posted above look great to me! I think we're almost there... |
|
Thanks @xylar, that's super helpful. Attached are updated mean state plots for year 100 of the 80km. It looks nicely spun-up to me, at least dynamically: |
|
@alicebarthel This is awesome progress! Is this ready for review? Are you planning on adding a visualization or analysis step to aid comparison with MITgcm https://mitgcm.readthedocs.io/en/latest/examples/baroclinic_gyre/baroclinic_gyre.html#model-solution? The heat flux figure you posted looks like a good comparison with Fig 2.7. Do you think we want the analogs to Figs 4.8 or 4.9? |
|
Thanks @cbegeman! For now, all the analysis is offline. Yes, there are a few more plots I want to make, including Figure 4.9b. Figure 4.8 may be good too - although at this stage the SSH contour looks good enough for me. Adding the barotropic streamfunction could be nice but feels lower priority for me.
At this stage, I am focusing on:
I welcome comments and suggestions as I work on this. |
How about keeping the long test and having analysis/viz steps included in that test (and plot the last time slice in the output) but not include these steps in the performance test? I think it's reasonable to have the users change the duration. I didn't read through the docs yet, but let's make sure that ~50 year duration is recommended there. |
| if self.name == '3_year_test': | ||
| replacements = {'config_do_restart': '.true.', | ||
| 'config_start_time': "'file'"} | ||
| self.update_namelist_at_runtime(replacements) |
There was a problem hiding this comment.
This isn't working because the name of the step is always forward, not 3_year_test. One fix is:
| if self.name == '3_year_test': | |
| replacements = {'config_do_restart': '.true.', | |
| 'config_start_time': "'file'"} | |
| self.update_namelist_at_runtime(replacements) | |
| if self.test_case.name == '3_year_test': | |
| replacements = {'config_do_restart': '.true.', | |
| 'config_start_time': "'file'"} | |
| self.update_namelist_at_runtime(replacements) |
Or I think it might be more logical to store the long argument as an attribute and use it here:
| if self.name == '3_year_test': | |
| replacements = {'config_do_restart': '.true.', | |
| 'config_start_time': "'file'"} | |
| self.update_namelist_at_runtime(replacements) | |
| if self.long: | |
| replacements = {'config_do_restart': '.true.', | |
| 'config_start_time': "'file'"} | |
| self.update_namelist_at_runtime(replacements) |
Merge branch 'add-mitgcm-moc-analysis' into add-mitgcm-baroclinic-gyre
| print(f'analytical bottom T: {val_bot} at \ | ||
| depth : {bottom_depth}') |
There was a problem hiding this comment.
Here and in similar places, this is the preferred way to continue an f-string on a subsequent line:
| print(f'analytical bottom T: {val_bot} at \ | |
| depth : {bottom_depth}') | |
| print(f'analytical bottom T: {val_bot} at ' | |
| f'depth : {bottom_depth}') |
There was a problem hiding this comment.
Thanks @xylar , I modified these. Let me know if I missed others.
6aeafb9 to
5d571a9
Compare
|
@xylar @cbegeman This is ready for a review. I ran the performance and 3_year tests on Chrysalis without issue. I also ran the 3_year test for longer (50years, which takes ~2hours for 80km set-up). |
|
@alicebarthel, that looks awesome! I'm glad we got the surface restoring worked out. I'll review it tomorrow. |
xylar
left a comment
There was a problem hiding this comment.
@alicebarthel, this is some amazing work! It's very nearly there!
I was able to run the 80km tests without a hitch! I'm running the 20 km tests now. In the meantime, I have several small suggestions that you could make, or we could discuss further.
| BaroclinicGyre | ||
|
|
||
| GyreTestCase | ||
| GyreTestCase.configure | ||
|
|
||
| forward.Forward | ||
| forward.Forward.run | ||
|
|
||
| initial_state.InitialState | ||
| initial_state.InitialState.run |
There was a problem hiding this comment.
The other classes should be added here as well (CullMesh, Moc and Viz).
There was a problem hiding this comment.
Thanks! Is this supposed to be alphabetical or does the order matter?
There was a problem hiding this comment.
Yes, alphabetical is easiest.
| At this stage, the test case is available at 80-km and 20-km horizontal | ||
| resolution. By default, the 15 vertical layers vary linearly in thickness with depth, from 50m at the surface to 190m at depth (full depth: 1800m). | ||
|
|
||
| The test group includes 2 test cases, called ``performance_test`` for a short (10-day) run, and ``3_year_test`` for a 3-year simulation. Note that 3 years are insufficient to bring the standard test case to full equilibrium. Both test cases have 2 steps, |
There was a problem hiding this comment.
| The test group includes 2 test cases, called ``performance_test`` for a short (10-day) run, and ``3_year_test`` for a 3-year simulation. Note that 3 years are insufficient to bring the standard test case to full equilibrium. Both test cases have 2 steps, | |
| The test group includes 2 test cases, called ``performance_test`` for a short (3-time-step) run, and ``3_year_test`` for a 3-year simulation. Note that 3 years are insufficient to bring the standard test case to full equilibrium. Both test cases have 2 steps, |
| Framework | ||
| --------- |
There was a problem hiding this comment.
It seems like cull_mesh, moc and viz need to be added to this.
| maxloc = 'at lat = {} and z = {}m'.format( | ||
| latbins[idx[-1]].values, int(dsMesh.refInterfaces[idx[0]].values)) | ||
| maxval = 'max MOC = {:.1e} at lat={}-{}'.format( | ||
| round(np.max(moc[:, 175]), 1), | ||
| latbins[175 - 1].values, latbins[175].values) |
There was a problem hiding this comment.
Ideally, break this into several lines where you store these various inputs in variables and then use f-strings rather than the .format() methods to put them in place.
cbegeman
left a comment
There was a problem hiding this comment.
I think this looks great! I just visually inspected the code. Would you like me to run tests on any particular machine or build docs?
| # Number of vertical levels | ||
| vert_levels = 15 | ||
|
|
||
| # Total water column depth |
There was a problem hiding this comment.
| # Total water column depth | |
| # Total water column depth in m |
| # the type of vertical grid | ||
| grid_type = linear_dz | ||
|
|
||
| # the linear rate of thickness increase for linear_dz |
| restoring_temp_timescale = 30. | ||
|
|
||
| # config options for the mean state visualization | ||
| [mean_state_viz] |
There was a problem hiding this comment.
| [mean_state_viz] | |
| [baroclinic_gyre_viz] |
There was a problem hiding this comment.
Thanks! I modified this to include both viz and moc calculation parameters.
| :py:class:`compass.mesh.QuasiUniformSphericalMeshStep`. Then, the mesh is | ||
| culled to keep a single ocean basin (with lat, lon bounds set in `.cfg` file). A vertical grid is generated, | ||
| with 15 layers of thickness that increases linearly with depth (10m increase by default), from 50m at the surface to 190m at depth (full depth: 1800m). | ||
| Finally, the initial temperature field is initialized with a vertical profile to approximate the discrete values set in the `MITgcm test case <https://mitgcm.readthedocs.io/en/latest/examples/baroclinic_gyre/baroclinic_gyre.html>`_, uniform in horizontal space. The surface and bottom values are set in the `.cfg` file. Salinity is set to a constant value (34 psu, set in the `.cfg` file) and initial |
There was a problem hiding this comment.
Break up into multiple lines here and elsewhere. I think max length should be 89 char.
There was a problem hiding this comment.
Yes, 79 characters actually. The width of a default terminal is 80, so that's the reasoning.
| :titlesonly: | ||
|
|
||
| baroclinic_channel | ||
| baroclinic_gyre |
There was a problem hiding this comment.
@xylar Is this what you meant in your review of the users_guide above?
xylar
left a comment
There was a problem hiding this comment.
Looks great! Thanks for making the requested changes.












This PR aims to add the MITgcm baroclinic test case to compass. Started as a Work In Progress [WIP] PR to allow discussion and debugging before merging.
Checklist
api.rst) has any new or modified class, method and/or functions listedTestingin this PR) any testing that was used to verify the changes