From 652e4ee71d610a3b75953fa2d48c86fc405c83a9 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 30 Mar 2026 21:41:17 -0400 Subject: [PATCH] Add AI-assistance policy, agent instructions, and code style docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add three new documentation files and supporting pointer files to guide both human contributors and AI coding assistants: - docs/Consortium-policy-on-AI.md : Project policy on AI-assisted contributions, authored by Hallberg and Ward. Establishes that a human contributor is accountable for all submitted code, requires disclosure of AI assistance in PRs, and catalogs specific risks (physical correctness, comprehension debt, vacuous tests, code churn, unsafe code). Permits AI for development assistance, debugging, documentation, CI triage, and PR review; prohibits autonomous contribution without human oversight. - docs/AGENTS.md : Technical instructions for AI coding assistants covering the parameter system (get_param, _BUG flags, ANSWER_DATE), diagnostics (registration, posting, masking conventions), the test suite (.testing/ with tc0–tc4, test categories, verification via bitwise-identical checksums), git workflow (fork-based branching, commit message conventions with */+ prefixes, PR description style), physics domain knowledge, common development tasks (new parameterizations, diagnostics, runtime parameters, bug fixes), architecture constraints (infra/framework layering), and defensive programming practices. - docs/Code-style.md : Fortran code style guide migrated from the wiki and extended with sections on module structure, naming conventions, memory macros (SZI_, SZIB_, etc.), the dimensional unit annotation system ([rescaled ~> MKS]), and Doxygen documentation requirements. The line-length guideline is set to 120 characters to match what trailer.py and the GitHub Action enforce. Pointer files so AI tools auto-discover the conventions: - CLAUDE.md (Claude Code) — uses @docs/AGENTS.md directive - AGENTS.md (OpenAI Codex / OpenCode) — links to docs/AGENTS.md - .github/copilot-instructions.md (GitHub Copilot) — links to docs/AGENTS.md Also updates existing documentation: - README.md: expanded project description, added resource links (developer wiki, forum, CVMix, TEOS-10, GOTM) - docs/code_organization.rst: updated directory tree to reflect current layout (added FMS2, nuopc_cap, timing_tests, unit_tests; removed mct_cap; added driver descriptions) - docs/about.rst: fixed typos - docs/front_page.md: updated link to Code-style.md - docs/README.md: pointed Doxygen style references to docs/Code-style.md instead of the retired wiki pages - docs/Doxygen_* were modified to include new markdown files And, for full disclosure, copilot/Claude Opus 4.6 was used to reconcile the redundant or conflicting information between our first draft of the docs (on google drive) and files in the repository. --- .github/copilot-instructions.md | 1 + AGENTS.md | 1 + CLAUDE.md | 1 + README.md | 22 ++- docs/AGENTS.md | 292 ++++++++++++++++++++++++++++ docs/Code-style.md | 330 ++++++++++++++++++++++++++++++++ docs/Consortium-policy-on-AI.md | 61 ++++++ docs/Doxyfile_nortd | 2 + docs/Doxyfile_nortd_latex | 2 + docs/Doxyfile_rtd | 2 + docs/README.md | 15 +- docs/about.rst | 8 +- docs/code_organization.rst | 114 ++++++----- docs/front_page.md | 2 +- 14 files changed, 786 insertions(+), 67 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 docs/AGENTS.md create mode 100644 docs/Code-style.md create mode 100644 docs/Consortium-policy-on-AI.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..67caa10a62 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1 @@ +Read and follow the instructions in [docs/AGENTS.md](../docs/AGENTS.md). diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..148d55e588 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +Read and follow the instructions in [docs/AGENTS.md](docs/AGENTS.md). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..6e5a268f2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@docs/AGENTS.md diff --git a/README.md b/README.md index 17b0a3661c..63beca91cc 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,28 @@ # MOM6 -This is the MOM6 source code. +MOM6 (Modular Ocean Model, version 6) is a next-generation open-development-source ocean model developed by a consortium of institutions. It uses a modern Fortran codebase solving the primitive equations for ocean dynamics on an Arakawa C-grid. +- Arbitrary Lagrangian-Eulerian (ALE) vertical coordinate +- Boussinesq and non-Boussinesq modes +- Flexible equation of state (Wright, TEOS-10, linear, Roquet (TEOS-10), ...) +- Comprehensive parameterization library (ePBL, KPP, lateral mixing, tidal forcing) +- Coupled to SIS2 or CICE (sea ice), ice shelves, and Earth system models via the FMS or NUOPC couplers, or run in stand-alone ocean-only configurations +- Dimensional unit scaling for consistency testing -# Where to find information -Start at the [MOM6-examples wiki](https://github.com/NOAA-GFDL/MOM6-examples/wiki) which has installation instructions. +# Where to find information -[Source code documentation](http://mom6.readthedocs.io/) is hosted on read the docs. +- [MOM6-examples wiki](https://github.com/NOAA-GFDL/MOM6-examples/wiki) -- installation instructions and tutorials +- [Source code documentation](https://mom6.readthedocs.io/en/main/) -- hosted on Read the Docs +- [Developers wiki](https://github.com/NOAA-GFDL/MOM6/wiki) -- developer guides and conventions +- [Developer workflow](https://github.com/NOAA-GFDL/MOM6/wiki/Developer-workflow) +- [Runtime parameter system](https://github.com/NOAA-GFDL/MOM6/wiki/MOM6-run-time-parameter-system) +- [Repository policies](https://github.com/NOAA-GFDL/MOM6-examples/wiki/MOM6-repository-policies) +- [MOM6 forum](https://bb.cgd.ucar.edu/cesm/forums/mom6.148/) +- [CVMix](https://github.com/CVMix/CVMix-src) -- Community Vertical Mixing +- [TEOS-10 (GSW)](http://www.teos-10.org/) -- Gibbs Seawater +- [GOTM](https://gotm.net/) -- General Ocean Turbulence Model # What files are what diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 0000000000..49356aea05 --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,292 @@ +# MOM6 rules for agent-assisted development + +## First Steps + +**At the start of every session**, remind the user that MOM6 has a policy on AI-assisted +contributions in `Consortium-policy-on-AI.md`. + +Read `Code-style.md` before writing or modifying any code. + +See `code_organization.rst` for a high-level overview of the source directory tree. + +## Parameter System + +Runtime parameters are read via `get_param()`, not hardcoded: + +```fortran +#include "version_variable.h" +character(len=40) :: mdl = "MOM_module_name" + +call log_version(param_file, mdl, version, "") +call get_param(param_file, mdl, "PARAM_NAME", CS%variable, & + "Description of this parameter.", & + units="m s-1", default=1.0, scale=US%m_s_to_L_T) +``` + +- Parameters documented in auto-generated `MOM_parameter_doc.all` files +- Use `scale=` argument for unit conversion from MKS input to internal units +- Always provide `default=` when sensible; use `fail_if_missing=.true.` otherwise +- Use `do_not_log=.not.CS%Feature` to suppress logging when a parent feature is inactive + +### Answer-Changing Parameters: `_BUG` Flags and `ANSWER_DATE` + +When a bug fix or improvement changes numerical answers, MOM6 uses two mechanisms to preserve backward compatibility: + +**`_BUG` flags**: Boolean parameters that retain old (buggy) behavior by default: +```fortran +call get_param(param_file, mdl, "ENABLE_BUGS_BY_DEFAULT", enable_bugs, & + default=.true., do_not_log=.true.) ! This is logged from MOM.F90. +call get_param(param_file, mdl, "OBC_TEMP_SALT_NEEDED_BUG", OBC%ts_needed_bug, & + "If true, recover a bug that OBC temperature and salinity can be ignored "//& + "even if they are registered tracers in the rest of the model.", & + default=enable_bugs) +``` +- Name format: `FEATURE_BUG` (e.g., `VISC_REM_BUG`, `FRICTWORK_BUG`, `KAPPA_SHEAR_ITER_BUG`) +- Default is `.true.` (bug ON, old behavior preserved) +- Description starts with "If true, recover a bug that..." +- Users opt into the fix by setting to `.false.` + +**`ANSWER_DATE` flags**: Integer dates selecting algorithm versions: +```fortran +call get_param(param_file, mdl, "HOR_DIFF_ANSWER_DATE", CS%answer_date, & + "...", default=99991231) +``` +- Format: `YYYYMMDD` (e.g., `20251231`) +- `DEFAULT_ANSWER_DATE` provides a single knob to update all answer-date defaults +- `ENABLE_BUGS_BY_DEFAULT=False` activates all bug fixes (recommended for new configurations) + +## Diagnostics + +### Registration Pattern + +```fortran +CS%id_field = register_diag_field('ocean_model', 'field_name', diag%axesTL, Time, & + 'Long description of the field', units='m s-1', conversion=US%L_T_to_m_s) +``` + +### Posting Pattern + +```fortran +if (CS%id_field > 0) call post_data(CS%id_field, field_array, CS%diag) +``` + +Key conventions: +- `conversion=` handles unit scaling so output is always in MKS +- `v_extensive=.true.` for vertically integrated quantities +- Guard computation with `if (id > 0)` to avoid unnecessary work +- Standard diagnostic name prefixes follow CMOR conventions when applicable + +### Masking and Missing Values + +- **Never set diagnostic arrays to a missing value** before passing to `post_data()`. Masking of land/invalid points is handled automatically by the diagnostics infrastructure based on the diagnostic's registered axes. +- **Do not pass `mask=` to `post_data()`** for non-static diagnostics on standard grids -- the infrastructure applies the correct mask automatically. +- **Do pass `mask=`** for static fields (`is_static=.true.`), non-standard masks, or sub-domain-sized arrays. +- **Never compare field values against `missing_value`** in unit-conversion code -- rescaling can cause valid data to coincidentally match the missing value sentinel. + +## Testing + +### Test Suite Overview + +The `.testing/` directory provides comprehensive verification. Build and run: + +```bash +make -C .testing -j build/symmetric/MOM6 # Build reference executable +make -C .testing -j test # Run full test suite +make -C .testing -j build.unit # Build unit tests +make -C .testing -j run.unit # Run unit tests +``` + +### Test Categories + +| Test | Verifies | +|------|----------| +| `test.grid` | Symmetric vs asymmetric grids produce identical results | +| `test.layout` | Serial vs parallel decomposition identical | +| `test.rotate` | Rotational invariance | +| `test.restart` | Continuous run vs restart-and-continue identical | +| `test.repro` | DEBUG and REPRO builds identical | +| `test.openmp` | Serial vs OpenMP identical | +| `test.nan` | NaN-initialization doesn't affect results | +| `test.dim.{t,l,h,z,q,r}` | Dimensional rescaling invariance (time, length, thickness, depth, enthalpy, density) | +| `test.regression` | Current code vs target branch (PRs only) | + +### Test Configurations + +- `tc0` -- Unit tests +- `tc1` / `tc1.a` / `tc1.b` -- Benchmark (split RK2, unsplit RK3, unsplit RK2) +- `tc2` / `tc2.a` -- ALE with tides / sigma-coordinate PPM_H4 +- `tc3` -- Open boundary conditions +- `tc4` -- Sponges and I/O initialization + +### Verification Method + +- `ocean.stats` -- total energy at machine precision +- `chksum_diag` -- mean/min/max/bitcount checksums in physical domain +- Tests pass only when output is **bitwise identical** between configurations + +### Style Checking + +```bash +./.testing/trailer.py -e TEOS10 -l 120 src config_src +``` + +Checks for tabs, trailing whitespace, and line length violations. + +## Git Workflow & Contribution + +### Branch Strategy + +- **Work on forks**, not branches on the primary repository +- **Branch from the fork's default branch** (e.g., `dev/gfdl`, `dev/ncar`) for all new work +- **Never rebase a pushed branch** +- The human contributor submits changes via pull requests to the fork's default branch (e.g., `dev/gfdl`); merges to `main` are done by consortium consensus + +### Commit Message Format + +``` +Short imperative summary (50 chars if at all possible) + +Detailed explanation wrapped at 72 characters. +Describe what was changed and why. Reference issues with #NNN. +All answers are bitwise identical. +``` + +Conventions from the lead developers: +- **`*` prefix** on title if the commit changes numerical answers (checksums) +- **`+` prefix** on title to indicate new public interfaces or parameters +- **`*+` or `+*`** when both answer-changing and adding new interfaces +- No prefix for refactoring, cleanup, or comment-only changes that are bitwise identical +- **Always state impact on numerical results**: "All answers are bitwise identical" or explain what changes +- **Multi-commit PRs**: introduce infrastructure first, use it in a second commit +- **Minimize public scope**: only export symbols needed by other modules; remove from `public` when refactoring makes a symbol internal-only +- **Comment closing `enddo`/`endif`** for non-trivial nested loops: `enddo ! n-loop for segments` + +### PR Description Style + +1. Lead with a clear explanation of what changed and why +2. Quantify scope (e.g., "across 26 files", "in 7 places") +3. For answer-changing PRs, provide scientific justification +4. State the bitwise-identical guarantee (or explain what changes and why) +5. When a fix could change answers, protect with a `_BUG` flag or `ANSWER_DATE` parameter. New `_BUG` flags should default to `ENABLE_BUGS_BY_DEFAULT` so that users who have opted into all fixes get the new fix automatically; existing `_BUG` flags may already default to `.false.` if the fix has been broadly adopted. + +### CI Pipeline + +On every push and PR, GitHub Actions runs: +1. Style and Doxygen checks +2. Builds across 8 configurations (symmetric, asymmetric, repro, openmp, target, opt, coverage, coupled API) +3. All test groups in parallel +4. Code coverage reporting +5. For PRs: regression testing and timing comparison against target branch + +## Physics Domain Knowledge + +### Governing Equations +- Hydrostatic primitive equations optionally with Boussinesq approximation +- ALE vertical coordinate: Lagrangian dynamics with periodic remapping +- Split barotropic-baroclinic time stepping (RK2 split or unsplit RK3) +- Free surface dynamics (implicit barotropic solver) + +### Numerical Methods +- Finite volume on Arakawa C-grid (staggered: velocities at cell faces, tracers at centers) +- PPM (Piecewise Parabolic Method) for tracer advection and continuity +- Various reconstruction schemes: PLM, PPM, PQM, WENO, PLM-WLS +- Pressure gradient force via finite-volume integration +- Reproducing global sums for parallel reproducibility + +### Key Physical Parameterizations +- **ePBL**: Energetically consistent planetary boundary layer (Reichl and Hallberg) +- **KPP**: K-Profile Parameterization via CVMix +- **Gent-McWilliams/Redi**: Thickness and isopycnal diffusion +- **MEKE**: Mesoscale eddy kinetic energy budget +- **Zanna-Bolton**: Data-driven subgrid momentum closure +- **Tidal forcing**: Astronomical and self-attraction/loading + +## Common Development Tasks + +### Adding a New Parameterization +1. Create `MOM_new_param.F90` in the appropriate `src/parameterizations/` subdirectory +2. Define a control structure type (`new_param_CS`) with `private` members +3. Implement `new_param_init()`: read parameters via `get_param`, register diagnostics +4. Implement the main computational subroutine +5. Implement `new_param_end()` for cleanup +6. Wire it into the calling module (e.g., `MOM_diabatic_driver.F90`) +7. Document all variables with proper units +8. Add unit tests in `config_src/drivers/unit_tests/` if applicable +9. Run the full test suite: `make -C .testing -j test` + +### Adding a New Diagnostic +1. Add `integer :: id_new_diag = -1` to the control structure +2. Register in `_init` with `register_diag_field('ocean_model', 'name', axes, Time, ...)` +3. Compute and post with `if (CS%id_new_diag > 0) call post_data(CS%id_new_diag, array, CS%diag)` +4. Include `conversion=` for unit scaling to MKS output +5. Provide CMOR standard name when applicable + +### Adding a Runtime Parameter +1. Add member to control structure with units documentation +2. Call `get_param(param_file, mdl, "PARAM_NAME", CS%param, "description", units="...", default=...)` +3. Use `scale=` for dimensional conversion from MKS input +4. If the parameter could change answers, default to preserving existing behavior + +### Fixing a Bug +- Always state whether the fix changes answers in the commit message +- **Any change that alters existing numerical answers** -- whether a bug fix, accuracy improvement, or algorithmic reorganization -- must provide a runtime parameter (`_BUG` flag or `ANSWER_DATE`) to toggle between old and new behavior, with the default preserving old behavior +- This applies even when the developer's tests show negligible differences -- existing users may be in production runs +- Trace through secondary effects before concluding the fix is safe +- Run `test.regression` to verify impact + +## Architecture: Infrastructure Layering + +MOM6 has a strict dependency hierarchy that must never be violated: + +``` +config_src/infra/ --> src/framework/ --> src/core/, src/parameterizations/, etc. +``` + +- **`config_src/infra/`** (FMS1/FMS2 wrappers) must **never** import from `src/framework/` +- **Code duplication** between infra and framework is acceptable to maintain this invariant +- FMS1 and FMS2 infra directories must expose the same public API +- API changes to infra-level functions must be checked against downstream consumers (SIS2, ice shelf code) + +## Defensive Programming + +- **Check `allocated()` / `associated()`** before accessing arrays tied to optional features (e.g., features controlled by runtime parameters like `FRAZIL` may not allocate all related arrays) +- **No short-circuit evaluation**: Fortran does not guarantee short-circuit evaluation; allocation checks must not appear in compound conditions. Convert `if (allocated(arr) .and. (condition))` to nested if-blocks +- **Type-correct comparisons**: when comparing real-valued masks, use `== 1.` not `== 1` +- **FATAL error messages** should include: file name, subroutine name, and the specific condition or input that triggered the error +- **Validate user inputs early**: check for duplicates, overflow, and missing required fields in configuration parsing; include the problematic input string in error messages +- **`!###` comment prefix** marks known bugs or inaccurate expressions that change answers and will be cleaned up later -- do not modify code marked with `!###` unless explicitly asked + +## Common Pitfalls + +In addition to the code style rules in `Code-style.md`: + +1. **Forgetting units in comments**: every `real` variable needs `[units]` (see `Code-style.md`) +2. **Answer-changing without a `_BUG` flag**: any numerical change requires a runtime parameter to preserve old behavior +3. **Unnecessary `mask=` in `post_data()`**: the infrastructure handles masking automatically for non-static diagnostics +4. **Accessing unallocated optional arrays**: always check `allocated()` before using arrays tied to optional features + +### Key References + +The project bibliography lives in `docs/references.bib` and `docs/zotero.bib`. Consult these +when citing prior work in Doxygen documentation or commit messages. + +## AI Assistant Behavior + +- **Follow existing patterns**: read surrounding code before making changes +- **Document all units**: every real variable gets `[units]` annotation +- **Parenthesize arithmetic**: explicit grouping for reproducibility +- **State answer impact**: always note whether changes are bitwise identical +- **Use `get_param`**: never hardcode parameters; always read from parameter files +- **Register diagnostics properly**: guard with `if (id > 0)`, use `conversion=` +- **Maintain lifecycle**: implement `_init` and `_end` for new modules +- **Run tests**: `make -C .testing -j test run.unit` before the contributor submits a PR +- **Respect the C-grid**: use correct staggering (soft case convention for indices) +- **Write Doxygen comments**: `!>` for entities, `!<` for inline, with units +- **Write thorough commit messages**: explain both what changed and why in the commit body + +## Common Claude Mistakes + +This section catalogs recurring mistakes that Claude makes when working on MOM6 code. It should be updated as new patterns emerge from experience. + +*(No entries yet -- add mistakes here as they are discovered.)* + diff --git a/docs/Code-style.md b/docs/Code-style.md new file mode 100644 index 0000000000..f006638178 --- /dev/null +++ b/docs/Code-style.md @@ -0,0 +1,330 @@ +# MOM6 code style guide + +MOM6 makes use of Fortran2003 and later extensions but only when supported by all available compilers. We try to avoid the use of very modern Fortran constructs that can limit portability. To help keep the code readily understandable, this page makes recommendations about how to use or not use the various features of the modern Fortran language. + +Code style is typically a personal choice, but when styles clash it can lead to discord. These +standards have been adopted in an attempt to promote harmony and clarity. + +## White space + +- No tabs +- No trailing white space +- Indents should be consistent (same amount used in contiguous blocks) +- Preferred indent is 2 spaces + - "preferred" might understate the reaction invoked by other indent amounts! :wink: +- Continuation lines should be indented at least 4 spaces, but more space can be used if it helps align lines + - One exception is the continuation line after a simple `if` test with no `then`, which could be 2 space indent as though the `then` and `endif` were present. I.e., +``` + if (test) & + var = expression +``` +and +``` + if (test) then + var = expression + endif +``` +should have the same indenting on `var = expression` so that there would be no need to change the indenting if another statement were added to the `if` block, or if the latter expression were converted to the former. +- No white space between a function name and the opening parenthesis +- White space after all language token + - `if(a==0)` is legal fortran but bad style. Use `if (a==0)` instead. + - `if (a == 0)` is even better, since `==` is a language token. +- Use space around the equal sign in variable assignment, but not when using a named optional argument + - `a = b` is strongly preferred over `a=b` + - One exception is loop indices, where `do i=is,ie` is acceptable + - `call fn(arg1, arg_name=a)` is strongly preferred over `call fn(arg1, arg_name = a)` +- Use a space after the comma separating subroutine or function arguments in calls and declarations (e.g., `call fn(arg1, arg2, arg3)`), but usually not after the comma separating array indices for multidimensional arrays (e.g., `A(i,j,k) = B(i,j,k)`). + +## Line length + +Some compilers handle very long lines of code gracefully, but MOM6 needs to adhere to the Fortran standard, which is 132 characters for code, after any macro expansion. MOM6 does use macros for some memory declarations, +so we need to build in some added space in setting MOM6 guidelines: +- The target maximum length for MOM6 code lines is 120 characters, including comments. + - 80 character lines can be much easier to read if printed; smaller lines are encouraged where they make sense + +## Local variables + +- Local variable declarations appear after all the dummy argument declarations, and in the case of a function the return value. We often use ` ! Local variables` to delineate between the argument and local variable declarations. +- Local variables should preferably be descriptive multi-character names meaningful in their context, e.g. `del_rho_int` (delta rho at interface). + - If using a highly abbreviated or short name, the declaration **MUST** be commented. + - Units should be provided in the comments describing real variables. + - Multi-word names should use [snake_case](https://en.wikipedia.org/wiki/Snake_case) (e.g. `delta_rho`). + - snake_case admittedly used more characters than [camelCase](https://en.wikipedia.org/wiki/CamelCase) but unfortunately Doxygen interprets the Fortran standard too literally and throws away any attempts to use CamelCase. We briefly adopted CamelCase for new code but are systematically replacing it as we Doxygen-ize existing code. + +## Block constructs + +- `do` and `if` constructs should be terminated with the combined `enddo` and `endif` statements, respectively. +- All other block end statements separate the `end` token (e.g. `end program [label]`) + - Examples: `program`, `module`, `type`, `subroutine`, `function`, `interface`, `select` + +## Loop indices + +### Soft case convention +- `i`,`j`,`k` are used for cell-center, layer-center references, e.g. `h(i,j,k)`, `T(i+1,j,k)`. +- `I`,`J` are used for staggered, cell-edge references, e.g. `u(I,j,k)`, `v(i,J,k)`, `q(I,J,k)`, `u(I-1,j,k)`. We use a north-east staggering convention so the `I` means i+1/2 and `I-1` means i-1/2. +- `K` is used for the interface (between layer) references, e.g. `del_t(i,j,K) = T(i,j,K+1) - T(i,j,K)`. The vertical staggering is such that interface `K=1` is above layer `k=1` so that `K` means k-1/2 and `K+1` means k+1/2. + +## Global / module data + +- Absolutely **NO**! +- There are a few exceptions which are strictly for debugging non-shared memory applications. Do not use these as an excuse for adding module data. + +## Module use statements +- Modules may use interfaces, data-types, and constant parameters from other modules via module use statements + - Modules may not use variables from other modules via use statements + - All MOM variables are passed around as explicit arguments in interfaces. +- All module use statements must include the `, only` modifier + +## Implicit variables +- Absolutely **NO**! +- All MOM6 modules must declare `implicit none ; private` + - Top-level drivers (i.e., files declaring a program main()) only need `implicit none` + +## Array syntax + +- We **do not permit scalar-style expressions without the colon notation**, e.g. + - `tv%S = 0.` is forbidden. +- We do allow array syntax for whole array initialization, e.g. + - `tv%S(:,:,:) = 0.` +- We do allow array syntax for identical copies, e.g. + - `S_tmp(:,:,:) = tv%S(:,:,:)` +- We do not allow whole array-syntax for math expressions that include halos because halos are not guaranteed to have valid data: + - `tmp(:,:) = 1.0 / G%areaT(:,:)` might have zeros in the halo region. + - `call post_data(id_AT, G%areaT(:,:)*tv%(T(:,:,1))` is wrong because it can use uninitialized data in halos. + +## Data flow + +- All needed data is passed via arguments to subroutines and functions, or as the returned value of a function. +- All arguments must have declared intent, with the exception of pointers: i.e. `intent(in)`, `intent(out)`, `intent(inout)`. +- Opaque types are preferred, i.e. referencing members of types defined in other modules is discouraged. + +## Documentation in code + +- Do it when you are writing the code in the first place! +- All subroutines, functions, arguments, and elements of public types should be described in with Doxygen comments. +- All real variables should have a full physical description, including units. +- All comments should be clearly written and grammatically correct; American spelling is preferred. + +## Optimization for divides + +Divisions are prone to NaNs and relatively expensive. An optimizing compiler will often rearrange math which makes debugging divisions by zero harder to catch. +- Many common reciprocals are pre-computed + - Use `Q(i,j) * G%IareaT(i,j)` instead of `Q(i,j) / G%areaT(i,j)`. +- Never write `B / C * D` which is ambiguous to humans (not the compiler) + - Use `( B * D ) / C` +- Never double divide: `A / ( A + B / C)` + - Use `( A * C ) / ( A * C + B)` + + +## Arithmetic reproducibility + +Floating point operations are sensitive to the order of operations (associativity), which can not generally be guaranteed due to compiler serialization and optimization. + + +### Addition + +Addition operations must be done in pairs. When more than one addition is required, the order should be specified using parentheses. + +- This is bad: + - `z = a + b + c` +- This is good: + - `z = (a + b) + c` + +Ideally, the order of operation should be chosen to give the best accuracy. For example, if `a = 1.` `b = -1.` and `c = 1.e-20`, then the order should be chosen to preserve the residual value. + +- This is bad: + - `a + (b + c) == 0.` +- This is good: + - `(a + b) + c == 1.e-20` + +Not only does this impact reproducibility, but the second choice is more accurate and avoids a potential division by zero. + +All operations should be ordered, but no particular ordering is enforced. Contributors are encouraged to consider the most accurate order of operations. In some cases the order of sums can be chosen to give expressions that yield identical answers if the underlying horizontal coordinate is rotated by 90 or 180 degrees, which would define the preferred order of operations. + + +### `sum()` intrinsic + +We avoid the Fortran `sum()` intrinsic since the result is dependent on the order of operations within the summation. Using explicit loops allows us to define the order of summation. So +``` +a = sum(b(:)) +``` +should be +``` +a = 0. +do k = 1, nz + a = a + b(k) +enddo +``` +The `prod()` and `matmul()` intrinsics should also not be used. + + +### Global summation + +Floating point operations across MPI ranks are volatile, since the order can change depending on the state of the network. Functions such as `MPI_Reduce` will not generally be reproducible when used for floating point arithmetic. + +When performing summations over MPI ranks, use the `reproducing_sum` function. +``` +use MOM_coms, only: reproducing_sum +... +sum = reproducing_sum(array(:,:)) +``` + + +### Multiplication + +Multiplication is also non-associative and thus not reproducible, but the impact is typically small. Results may depend on the order of operations, most often in the least significant bit of the fractional component. + +In single precision, if `a = b = 1 + 2**-23` and `c = 1.5`, then the following calculations differ: + +- `(a*b)*c = 1.50000036` +- `a*(b*c) = 1.50000048` + +Parentheses in multiplication operations are currently not enforced, but contributors should consider using them when applicable. + + +### Transcendental functions + +Use of transcendental functions, such as trigonometric functions, non-integer powers, and logarithms, are often implementation-dependent and should be avoided when possible. + + +### Exponent operator + +The exponent operator, `a**b` should be used sparingly, since compilers will often internally replace it with `pow(a, b)`, which is often computed as a transcendental function, `exp(b * log(a))`. Even small integral power, such as `a**3`, have been known to be replaced with `pow(a, 3)`. To maximize reproducibility, integral powers should be explicitly computed, e.g. `a3 = a * a * a`. + +Square roots (`a**0.5`) should always use the `sqrt()` intrinsic. An IEEE-754 compliant `sqrt` function must be exactly rounded. + +Cube roots (`a**(1./3.)`) should be avoided, the MOM6 intrinsic `cuberoot` should be used. This is not exactly rounded, but it is reproducible. + + +## Module structure + +Every module follows this pattern: + +```fortran +!> Brief module description +module MOM_module_name + +! This file is part of MOM6. See LICENSE.md for the license. + +use MOM_some_module, only : specific_symbol +use MOM_other, only : other_thing + +implicit none ; private + +#include + +public :: exported_routine_1, exported_routine_2 + +!> Control structure for this module +type, public :: module_CS ; private + real :: param !< Description [units] + integer :: id_diag = -1 !< Diagnostic ID for some_field +end type module_CS + +contains + +!> Initialize the module, read parameters, register diagnostics +subroutine module_init(Time, G, GV, US, param_file, diag, CS) + ! ... call log_version, get_param, register_diag_field ... +end subroutine module_init + +!> Deallocate module memory +subroutine module_end(CS) + ! ... cleanup ... +end subroutine module_end + +!> \namespace MOM_module_name +!! Extended description, references, and equations +end module MOM_module_name +``` + +Key rules: +- Most modules have `_init` and `_end` subroutines for lifecycle management +- `! Local variables` comment separates dummy arguments from local declarations +- **Prefer `allocatable` over `pointer`** for control structure members + + +## Naming conventions + +- **Files**: one module per file; module name must match file name (e.g., `MOM_something.F90` contains module `MOM_something`) +- **Control structures**: `module_CS` (e.g., `energetic_PBL_CS`), always `public` but opaque (with `private` contents) +- **Diagnostic IDs**: `id_diag_name`, initialized to `-1` +- **Inverses**: prefix with `I` (e.g., `IdxCu` = `1/dxCu`, `IareaT` = `1/areaT`) +- **Grid objects**: `G` (ocean_grid_type), `GV` (verticalGrid_type), `US` (unit_scale_type) +- **Public functions**: self-documenting names; private helpers may use short names + + +## Memory macros + +Array dimensions use preprocessor macros from `MOM_memory.h`: +- `SZI_(G)`, `SZJ_(G)`, `SZK_(GV)` for explicit-shape cell-center arrays +- `SZIB_(G)`, `SZJB_(G)`, `SZKB_(GV)` for explicit-shape face/edge-point arrays +- `NIMEM_`, `NJMEM_`, `NKMEM_` for allocatable arrays + + +## Unit documentation + +MOM6 uses a dimensional annotation system for every real variable. Units are documented in square brackets at the end of comments, using a two-part notation: + +``` +[rescaled_dimensions ~> MKS_equivalent] +``` + +### Dimensional symbols + +| Symbol | Physical Dimension | MKS Unit | +|--------|-------------------|----------| +| Z | Vertical depth/distance | m | +| L | Horizontal length | m | +| T | Time | s | +| H | Layer thickness | m (Boussinesq) or kg m-2 | +| R | Density | kg m-3 | +| Q | Enthalpy | J kg-1 | +| C | Temperature | degC | +| S | Salinity | ppt | +| A | Arbitrary/generic units | a | + +### Examples + +```fortran +real :: velocity !< Horizontal velocity [L T-1 ~> m s-1] +real :: pressure !< Hydrostatic pressure [R L2 T-2 ~> Pa] +real :: thickness !< Layer thickness [H ~> m or kg m-2] +real :: diffusivity !< Vertical diffusivity [Z2 T-1 ~> m2 s-1] +real :: slope !< Isopycnal slope [Z L-1 ~> nondim] +real :: efficiency !< Mixing efficiency [nondim] +real :: field !< A field in arbitrary units [A] +real :: Z_to_m !< Scaling factor [m Z-1 ~> 1] +``` + +### Unit annotation rules + +1. **Every real variable** must have units in `[brackets]` at the end of its comment +2. **Canonical symbol ordering**: consistent order (e.g., `H L2` not `L2 H`) +3. **Boussinesq variants first**: `[H ~> m or kg m-2]` when units differ by approximation +4. **Simplified expressions only**: write `[T2 Z-1 ~> s2 m-1]`, not `[H Z T-1 / H Z2 T-3 = T2 Z-1 ~> s2 m-1]` +5. **Exponent notation**: `m-1`, `s-2`, `kg-3` (no slashes like `1/m`) +6. **No extra spaces** inside brackets +7. **Nondimensional**: use `[nondim]` +8. **Arbitrary/generic**: use `[A]` or `[A ~> a]`, never `[arbitrary]` +9. **Scaling factors**: `[target source-1 ~> 1]`, e.g., `[Z m-1 ~> 1]` + + +## Doxygen documentation + +### Comment syntax + +- `!>` for documentation comments on the following entity +- `!<` for inline documentation on the preceding entity (same line) +- `!!` for multi-line continuation (no blank lines between) +- `!>@{` and `!>@}` for grouping related declarations + +### Requirements + +- **All public subroutines/functions**: `!>` header describing purpose +- **All arguments**: documented with `!<` or `!>` including units +- **All type members**: documented with `!<` including units +- **All real variables**: must include physical description and units +- **Equations**: LaTeX with `\f$ ... \f$` (inline) or `\f[ ... \f]` (display) +- **Extended descriptions**: placed before `end module` using `\namespace` + diff --git a/docs/Consortium-policy-on-AI.md b/docs/Consortium-policy-on-AI.md new file mode 100644 index 0000000000..5388c3d249 --- /dev/null +++ b/docs/Consortium-policy-on-AI.md @@ -0,0 +1,61 @@ +# Policy for AI-generated code in MOM6 + +## Guiding Principle + +AI coding assistants are welcome in MOM6 development the same way any other tool is welcome — with the expectation that a human contributor is responsible for everything they submit. AI use is permitted when it supports a contributor's comprehension of the code; it is not permitted as a substitute for that comprehension. + + +## Contributor Responsibility + +Every contribution to MOM6 has a human author who is accountable for its correctness, physical consistency, and conformance to MOM6 coding standards. Every contribution must have a clearly articulated purpose that is succinctly documented in the commit messages and pull request descriptions. +Reviewers may ask any contributor, "Do you understand why this works?" and “Why are you suggesting this?” These questions are always appropriate, and a satisfactory answer is always expected. +Code that the contributor cannot explain should not be submitted. + + +## Disclosure + +Contributors must disclose AI assistance in any pull request or commit where AI tooling materially shaped the submitted code. The tool is not credited as an author; the disclosure is for the benefit of reviewers. +A brief note in the PR description is sufficient, e.g. "Note that an AI tool was used in making this contribution" + + +## Risks of AI-Assisted Code + +The fact that AI-generated code compiles and passes existing tests is not sufficient evidence of correctness. Sign errors, unit mismatches, and flux miscalculations can pass a compiler and look plausible. AI models are capable of producing syntactically correct Fortran; they do not understand ocean physics. + +Contributors and reviewers should be alert to the following categories of risk: + +Physical correctness: AI tools have no understanding of the underlying science. Parameterizations, numerical schemes, and flux calculations must be verified by a human with domain knowledge, not inferred to be correct because the code runs. +Comprehension debt: If a contributor does not fully understand code they have submitted, that gap compounds over time as the code is further modified, potentially again with AI assistance. See also Section on responsibility. +Vacuous tests: AI-generated tests may pass without actually testing anything meaningful. Tests must be evaluated for genuine coverage and practical relevance. +Code churn: Modifying code without a compelling purpose impedes the process of developing useful capabilities. +Malicious or unsafe code: AI tools can be manipulated through prompt injection or may reproduce unsafe patterns from their training data. Contributors must review AI-suggested code for suspicious logic, unexpected network calls, file system access, or other behavior inconsistent with the intended change. Any code that cannot be straightforwardly explained by its stated purpose should be treated as suspect. + + +## Roles for AI in the Workflow + +The following uses are encouraged, with appropriate human oversight: + +Development assistance: exploring code, planning changes, drafting implementations, explaining unfamiliar code, suggesting refactors. +Debugging: identifying likely error sources, interpreting compiler or runtime messages. +Documentation: drafting docstrings and comments, prose descriptions. +CI triage: understanding feedback or messages on CI failures (e.g., summarizing logs, suggesting fixes for straightforward failures). +Reviewing Pull Requests: AI tools may be used to highlight possible issues in contributions, such as bugs or points of inconsistency with MOM6 practice and policy or clarifying that a contribution is pure refactoring. However, only a human reviewer may approve a pull request after fully understanding what the contributed code does. + +The following uses require particular caution: + +Autonomous code contribution with minimal human oversight is not currently accepted. +AI-generated tests must be verified to test something meaningful; vacuously passing trivial tests is a known failure mode. + + +## Equity + +Policy and tooling must not implicitly require paid LLM access. Workflows, templates, and guidance documents must remain useful to contributors without access to commercial AI tools. + + +## Legal and Institutional Considerations + +The IP status of AI-generated code remains unsettled in many countries including the United States, Australia, Korea, the European Union, and the United Kingdom. +Contributors should be aware of their institutional policies before using AI tools. +Contributors are responsible for ensuring that AI tool use complies with their employer's policies. +This consortium does not endorse any specific AI vendor or tool. + diff --git a/docs/Doxyfile_nortd b/docs/Doxyfile_nortd index 4a81c20bd7..4a0c282d32 100644 --- a/docs/Doxyfile_nortd +++ b/docs/Doxyfile_nortd @@ -860,6 +860,8 @@ WARN_LOGFILE = _build/doxygen_warn_nortd_log.txt INPUT = ../src \ front_page.md \ + Code-style.md \ + Consortium-policy-on-AI.md \ ../config_src/drivers/solo_driver \ ../config_src/memory/dynamic_symmetric \ ../config_src/external \ diff --git a/docs/Doxyfile_nortd_latex b/docs/Doxyfile_nortd_latex index 207e645195..f3f0b3f367 100644 --- a/docs/Doxyfile_nortd_latex +++ b/docs/Doxyfile_nortd_latex @@ -860,6 +860,8 @@ WARN_LOGFILE = _build/doxygen_warn_nortd_latex_log.txt INPUT = ../src \ front_page.md \ + Code-style.md \ + Consortium-policy-on-AI.md \ ../config_src/drivers/solo_driver \ ../config_src/memory/dynamic_symmetric \ ../config_src/external \ diff --git a/docs/Doxyfile_rtd b/docs/Doxyfile_rtd index 479c03e1b4..f427d7b6d4 100644 --- a/docs/Doxyfile_rtd +++ b/docs/Doxyfile_rtd @@ -810,6 +810,8 @@ WARN_LOGFILE = _build/doxygen_warn_rtd_log.txt # Note: If this tag is empty the current directory is searched. INPUT = ../src \ + Code-style.md \ + Consortium-policy-on-AI.md \ ../config_src/drivers/solo_driver \ ../config_src/memory/dynamic_symmetric \ ../config_src/external \ diff --git a/docs/README.md b/docs/README.md index 1bec91f288..6467aa06ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # Organization -The instructions for generation of MOM6 documentation is divided into three sections. +The instructions for generation of MOM6 documentation are divided into three sections. * [Documentation process](#documentation-process) * [Documentation syntax](#documentation-syntax) @@ -56,15 +56,16 @@ SRC/ drivers/ FMS_cap ice_solo_driver - mct_cap nuopc_cap solo_driver - unit_drivers + timing_tests + unit_tests external infra/ FMS1 + FMS2 memory/ - dynamic + dynamic_nonsymmetric dynamic_symmetric pkg/ CVMix-src @@ -91,14 +92,14 @@ SRC/ ## Doxygen -The [Doxygen](http://www.doxygen.org/) package is used to scan the source code for embedded documentation. Doxygen also automatically produces API documentation from arguments to subroutines, functions and member of types. The guide for using doxygen in MOM6 is hosted on the [MOM6 developer's wiki](https://github.com/NOAA-GFDL/MOM6/wiki/Doxygen). +The [Doxygen](http://www.doxygen.org/) package is used to scan the source code for embedded documentation. Doxygen also automatically produces API documentation from arguments to subroutines, functions and member of types. The guide for using doxygen in MOM6 is in [Code-style.md](Code-style.md). The majority of documentation is embedded in the comments of the source code. Additional documents have been added in the form of doxygen files (`*.dox`). The additional documents can be identified as those prefixed with an underscore (`_`) and have the `dox` extension. The content of the additional documents and source code should conform to usage as defined by the doxygen user and reference [manuals](https://www.doxygen.nl/manual/index.html). Further guidance is provided -on the [MOM6 developer's wiki](https://github.com/NOAA-GFDL/MOM6/wiki/Doxygen). +in [Code-style.md](Code-style.md). [Troubleshooting](details/Details.md) guides are provided with most commonly reported problems with MOM6 documentation. NOTE: Not all doxygen commands are supported through the sphinx documentation processor. Support can be added by adding an [issue](https://github.com/NOAA-GFDL/MOM6/issues) to the github repository. @@ -114,7 +115,7 @@ SRC/ MOM6.tags ``` -The main driver for doxygen is a configuration file. The content on [MOM6 developer's wiki](https://github.com/NOAA-GFDL/MOM6/wiki/Doxygen) uses the `Doxyfile_nortd` configuration file. +The main driver for doxygen is a configuration file. The content in [Code-style.md](Code-style.md) uses the `Doxyfile_nortd` configuration file. By default, the html directory is only available after processing the documentation. Please see [software operation](software-operation) on how to generate the pdf companion of the documentation. diff --git a/docs/about.rst b/docs/about.rst index 984e5776e8..981c60d8fc 100644 --- a/docs/about.rst +++ b/docs/about.rst @@ -13,14 +13,14 @@ Download, compile and run Installation, compilation and running are platform specific operations for which we can only provide templates (as is done in on the wiki) but for which MOM6 developers cannot possibly support since every platform is different. Normally a user needs to know where libraries (such as netcdf and MPI) and compilers are on their system but once these have - been established the documented compile process can be adpated to the local system. + been established the documented compile process can be adapted to the local system. User guide - `This site `_ provides a high-level overview of the model as well as the API reference (documentation + `This site `_ provides a high-level overview of the model as well as the API reference (documentation of source code). - The user guide is written in reStructuredText (.rst files) that reside in ``docs/`` of the `MOM6 source code `_. - The rst files are processed by sphinx and hosted on `readthedocs `_. + The user guide is written in reStructuredText (.rst files) that reside in ``docs/`` of the `MOM6 source code `_. + The rst files are processed by sphinx and hosted on `readthedocs `_. The API reference is generated documentation - we use doxygen for in-code documentation. The Fortran doxygen format is rather cumbersome for diff --git a/docs/code_organization.rst b/docs/code_organization.rst index 8e5ac39d57..aae9564bf0 100644 --- a/docs/code_organization.rst +++ b/docs/code_organization.rst @@ -3,7 +3,7 @@ Organization of the code The MOM6 source code is divided into a tree of directories (folders) to group related code (e.g. `src/core`) or similar modules (e.g. -`src/parametizations/vertical`). +`src/parameterizations/vertical`). The highest level of directories are: @@ -33,53 +33,45 @@ The highest level of directories are: The directory tree is:: MOM6 - ├── config_src - │   ├── drivers - │   │   ├── FMS_cap - │   │   ├── ice_solo_driver - │   │   ├── mct_cap - │   │   ├── nuopc_cap - │   │   ├── solo_driver - │   │   └── unit_drivers - │   ├── external - │   │   ├── GFDL_ocean_BGC - │   │   └── ODA_hooks - │   ├── memory - │   │   ├── dynamic_nonsymmetric - │   │   ├── dynamic_symmetric - ├── docs - │   └── images - ├── pkg - │   ├── CVMix-src - │   │   ├── ... - │   │   └── src - │   │      ├── drivers - │   │      └── shared - │   └── GSW-Fortran - ├── src - │ ├── ALE - │ ├── core - │ ├── diagnostics - │ ├── equation_of_state - │ │   └── TEOS10 - │ ├── framework - │ ├── ice_shelf - │ ├── initialization - │ ├── parameterizations - │ │   ├── CVmix -> ../../pkg/CVMix-src/src/shared - │ │   ├── lateral - │ │   └── vertical - │ ├── tracer - │ └── user - └── .testing - ├── tc0 - ├── tc1 - ├── tc1.a - ├── tc1.b - ├── tc2 - ├── tc2.a - ├── tc3 - └── tc4 + +-- config_src + | +-- drivers + | | +-- FMS_cap # GFDL coupler interface + | | +-- ice_solo_driver # Ice-only standalone + | | +-- nuopc_cap # NUOPC/CESM coupling + | | +-- solo_driver # Ocean-only standalone + | | +-- timing_tests # Performance benchmarks + | | +-- unit_tests # Unit test executables + | +-- external # Null hooks for optional components + | +-- infra # Framework interface (FMS1/FMS2 wrappers) + | | +-- FMS1 # FMS1 wrappers + | | +-- FMS2 # FMS2 wrappers + | +-- memory + | +-- dynamic_nonsymmetric + | +-- dynamic_symmetric + +-- docs + +-- pkg + | +-- CVMix-src # Community Vertical Mixing + | +-- GSW-Fortran # TEOS-10 Gibbs Seawater + +-- src + | +-- ALE # Vertical remapping/regridding + | +-- core # Dynamical core + | +-- diagnostics # Diagnostic calculations + | +-- equation_of_state # EOS implementations + | +-- framework # Infrastructure (diagnostics, I/O, parsing, domains) + | +-- ice_shelf # Ice shelf dynamics + | +-- initialization # Grid/state initialization + | +-- ocean_data_assim # Data assimilation + | +-- parameterizations + | | +-- lateral # Lateral parameterizations + | | +-- vertical # Vertical mixing + | +-- tracer # Tracer transport and specific tracers + | +-- user # Idealized configuration initialization + +-- .testing + +-- tc0 # Unit tests + +-- tc1 / tc1.a / tc1.b # Benchmark configurations + +-- tc2 / tc2.a # ALE with tides / sigma-coordinate + +-- tc3 # Open boundary conditions + +-- tc4 # Sponges and I/O initialization .. _config_src: @@ -88,9 +80,9 @@ The directory tree is:: `memory/dynamic_nonsymmetric/`, `memory/dynamic_symmetric/` One or none of `config_src/memory/dynamic_nonsymmetric/` or - `config_src/dynamic_symmetric/` can be included at compile time. If neither + `config_src/memory/dynamic_symmetric/` can be included at compile time. If neither is used then a `MOM_memory.h` file specific to the model configuration must be - present - this is known as a"static" compile with fixed layout and domain shape. + present - this is known as a "static" compile with fixed layout and domain shape. `external/` Contains "null" modules providing the API to optional components to use @@ -100,11 +92,15 @@ The directory tree is:: To use the actual ODA or BGC, add the appropriate source to the search paths . -`infra/FMS1` +`infra/` Contains MOM6-specific thin wrappers to all of the FMS types and routines that are used by MOM6. The code in this directory should only be called by the infrastructure-agnostic code in src/framework. +`drivers/ice_solo_driver/` + This driver produces a stand-alone ice-shelf executable that steps the + ice-shelf model without any ocean dynamics. + `drivers/solo_driver/` This driver produces an ocean-only executable with no other coupled components (no sea-ice, no atmosphere, etc.). It is the simplest @@ -115,6 +111,16 @@ The directory tree is:: compiling MOM6 along with at least a sea-ice model and possibly all other components in a coupled model. +`drivers/nuopc_cap/` + This driver provides a NUOPC-compliant interface for coupling MOM6 within + CESM or other NUOPC-based coupled systems. + +`drivers/unit_tests/` + Unit test executables for testing individual MOM6 components in isolation. + +`drivers/timing_tests/` + Performance benchmark executables for profiling MOM6 routines. + .. _src: `src/` @@ -137,9 +143,15 @@ The directory tree is:: Low-level wrappers for communication, diagnostics management, parsing of input parameters, time management, CPU clocks. +`ice_shelf/` + Ice shelf dynamics and thermodynamics. + `initialization/` Initialization of the horizontal grid, vertical coordinate, and the state. +`ocean_data_assim/` + Data assimilation interfaces. + `parameterizations/lateral` Sub-grid scale parameterization with fluxes primarily oriented in the lateral direction. diff --git a/docs/front_page.md b/docs/front_page.md index 4997244524..f036941b42 100644 --- a/docs/front_page.md +++ b/docs/front_page.md @@ -6,7 +6,7 @@ This documentation is also available as web-linkable pages hosted on [read the d If you are looking for a user guide, start at the [MOM6-examples wiki](https://github.com/NOAA-GFDL/MOM6-examples/wiki) which has installation instructions, links to tutorials, and more. -The APIs in MOM6 are documented using doxygen - you are viewing the result. A brief style guide for using doxygen in MOM6 is available at https://github.com/NOAA-GFDL/MOM6/wiki/Doxygen. +The APIs in MOM6 are documented using doxygen - you are viewing the result. A brief style guide for using doxygen in MOM6 is available in [docs/Code-style.md](Code-style.md). ***