Skip to content

Commit 4723810

Browse files
tclunemathomp4
andauthored
Integrate Extended Field Dictionary into MAPL3 (Phase 1 & 2, #4440) (#4577)
* Add extended FieldDictionary schema (Phase 1, #4440) - Add VerificationStatus typed enum (unverified/verified/cf_compliant) - Add ValidationMode typed enum (permissive/strict) - Extend FieldDictionaryItem with conserved, verification_status, physical_dimension, and provenance fields; conserved=true drives CONSERVE regrid method by default - Update FieldDictionary YAML parser to handle all new optional fields with backward-compatible defaults - Add FieldDictionaryConfig for cap.yaml parsing and is_exempt() predicate for item types that skip dictionary validation - Add field_dictionary_test.yaml with 20 fictitious test fields covering full v0.2.0 schema - Extend Test_FieldDictionary.pf with tests for all new types - Add GEOS_FieldDictionary v0.2.1 to components.yaml and .gitignore * Integrate FieldDictionary into parse_var_specs (Phase 2, #4440) - Add has_item() predicate to FieldDictionary to safely test key existence without crashing on NAG when key is absent (at() on missing key returns disassociated pointer under NAG). - Add optional field_dict_config parameter to parse_var_specs; load FieldDictionary from configured path at call start. - Apply dictionary defaults for units and long_name when standard_name is present and not overridden by YAML. - Warn (permissive) or fail (strict) when standard_name has no dictionary entry; skip entirely for exempt item types (expression). - Add optional long_name parameter to make_VariableSpec / VariableSpec so dictionary-derived long_name is stored. - Make parse_var_specs public in ComponentSpecParser for testing. - Add 8-test integration suite Test_FieldDictIntegration.pf covering dict defaults, YAML override, exempt types, permissive/strict modes, missing file, and multi-field cases. All 104 tests pass. * Address PR #4577 review comments (#4440) - FieldDictionaryConfig: restore default path to 'field_dictionary.yaml', remove warn_on_unverified/warn_on_non_cf booleans, add has_dictionary_path() predicate, use any() array syntax in is_exempt() - FieldDictionaryItem: simplify constructor with set-default-then-override idiom - parse_var_specs: build log_msg once for both _FAIL and lgr%warning; guard dict loading with has_dictionary_path(); keep dict_file_exists in outer scope for Fortran scoping compatibility - VariableSpec: guard get_regrid_method_from_field_dict_ on has_dictionary_path() before inquire; use _ASSERT for missing file - Test_FieldDictionary: update test_config_defaults for new defaults - CMakeLists.txt: install geos_field_dictionary.yaml to etc/ when present * Add field dictionary docs and fix CI-breaking _ASSERT (#4440) - VariableSpec: replace _ASSERT on missing dictionary file with silent rc=_FAILURE so get_regrid_param falls back to default regrid method when field_dictionary.yaml is absent (all existing GEOS runs) - docs/user_guide/docs/field_dictionary.md: new user guide covering configuration, schema, verification status, conserved flag, and experiment setup - docs/mapl3/field_dictionary_developer.md: new developer reference covering module APIs, integration in parse_var_specs, design notes - docs/user_guide/README.md: add section 3.11 linking to user guide * Fix gfortran preprocessor error: no multi-line _ASSERT args (#4440) gfortran's preprocessor does not handle macro arguments split across continuation lines. Replace multi-line _ASSERT calls in FieldDictionary.F90 with a local msg variable built before the call. * Fix gfortran associate+@assertEqual and unallocated long_name UB Two CI-blocking fixes: 1. Test_FieldDictIntegration.pf: replace associate(vs => var_specs%of(i)) + @assertEqual inside the block with a local VariableSpec variable assigned by copy. gfortran's pFUnit preprocessor loses the type of the associate name inside @assertEqual, causing a compile error. 2. parse_var_specs.F90: guard make_VariableSpec call with if (allocated(long_name)) to avoid passing an unallocated character(:),allocatable as character(*),optional — undefined behaviour that caused status=506 failures in NAG application ctests. * Revert long_name allocated() guard in parse_var_specs Reverts the if/else duplication added in the previous commit. The conditional is not the right fix; root cause needs investigation. * WIP: add _HERE debug trace in run_DSOSetServices * Remove debug _HERE trace from run_DSOSetServices * Move field dictionary lookup into make_VariableSpec via module singleton Architectural redesign: the field dictionary is now accessed through a module-level singleton (load_field_dictionary / get_field_dictionary) rather than being loaded and passed through parse_var_specs. Changes: - FieldDictionary.F90: add protected/private/target/save singleton 'the_field_dictionary', load_field_dictionary(), get_field_dictionary() - VariableSpec.F90: make_VariableSpec now calls get_field_dictionary() to fill units and long_name defaults from the singleton; remove FieldDictionaryConfig dependency; simplify get_regrid_method_from_field_dict_ to use the singleton instead of loading its own copy - parse_var_specs.F90: remove all field dictionary loading, lookup, and validation logic; drop field_dict_config argument - ComponentSpecParser.F90: remove field_dict_config from parse_var_specs interface; drop use of mapl3g_FieldDictionaryConfig - Test_FieldDictIntegration.pf: rewrite to test via make_VariableSpec and load_field_dictionary singleton; remove tests that were specific to the old parse_var_specs-based dict loading path * Call load_field_dictionary from MaplFramework%initialize Reads optional 'field_dictionary' key from mapl hconfig and loads the singleton dictionary at startup, before any component SetServices runs. If the key is absent, no dictionary is loaded and make_VariableSpec silently skips the lookup. * Simplify get_field_dictionary: always returns pointer to singleton Remove dictionary_is_loaded flag and associated() checks. The singleton is always a valid target; callers use has_item() to detect an empty (unloaded) dictionary. * Restore parse_var_specs.F90 to baseline (whitespace only diff) * Fix NAG build errors and runtime crash - FieldDictionary: move singleton declaration after type definition (NAG requires type to be defined before first use) - FieldDictionary: remove unused error_unit import and n_erased variable; reuse status for alias_map%erase() return value - FieldDictionary: guard add_aliases against empty StringVector to prevent disassociated pointer crash on default-constructed vector - FieldDictionary: use initialize-then-overwrite pattern instead of if/else for optional YAML fields (cleaner, same semantics) - FieldDictionaryItem: fix no-alias constructor to pass an explicit empty StringVector instead of zero-length character array literal - VariableSpec: explicitly use mapl3g_FieldDictionaryItem so FieldDictionaryItem type is visible under implicit none(type,external) * Make field dictionary mandatory at startup - MaplFramework: always load the dictionary; default path is geos_field_dictionary.yaml in CWD if field_dictionary: key absent - VariableSpec: assert standard_name is present in the dictionary (hard failure instead of silent skip) - Skip dict lookup for compound vector names '(name1,name2)' since these are not dictionary keys but encode two component names - Add required CF entries to field_dictionary_test.yaml for tests that pass standard_name for non-dict reasons (air_temperature, air_pressure PLE/PL, A) - Load field_dictionary_test.yaml in @before of affected test suites - configure_file() to copy field_dictionary_test.yaml to binary dir * Soften field dictionary enforcement to warn+skip GOCART and other external components may have standard_names not yet in the dictionary, and CI environments may not have the dict file at the default path. Hard failures would break those cases. - MaplFramework: catch load failure and log a warning instead of propagating the error; the dictionary remains empty and lookups are silently skipped - VariableSpec: replace _ASSERT on missing standard_name with a pflogger warning; units/long_name defaults are simply not applied Hard enforcement can be added in a follow-on once all components are updated to include entries in geos_field_dictionary.yaml. * Update CMakeLists.txt Agreed. Co-authored-by: Matt Thompson <matthew.thompson@nasa.gov> * Fix field dict init: use inquire() to avoid thrown exception Catching a non-zero rc after calling load_field_dictionary() does not suppress the pFUnit exception already thrown by MAPL_Verify inside the call. Use Fortran inquire() to check file existence before attempting to open, so ESMF_HConfigCreate is never called on a missing file and no exception is thrown. Behavior: - Default path absent: warn + continue (no exception) - Explicit path absent: hard fail via _ASSERT - File present: load normally via _RC * Fix CMakeLists install to support all mepo clone styles for GEOS_FieldDictionary mepo can clone subrepos with no prefix, @ prefix, or @ suffix. Loop over all three directory names so the install works regardless of clone style, as suggested by mathomp4 in PR #4577 review. * Update field dictionary docs to reflect current implementation - Default filename is geos_field_dictionary.yaml (not field_dictionary.yaml) - Missing default = warning + continue; only explicit path missing is fatal - Rewrite developer doc integration section: lookup is in make_VariableSpec, not parse_var_specs; add MaplFramework initialization description with explanation of why inquire() is used before load_field_dictionary * Address darianboggs PR review comments - Fix inconsistent indentation in FieldDictionary.F90 (type body and get_item) - Fix extra-space indentation on parse_var_specs in ComponentSpecParser.F90 - Use to_lower() in ValidationMode and VerificationStatus string constructors for truly case-insensitive parsing (not just lower/UPPER) - Add missing @AssertTrue(UNVERIFIED /= CF_COMPLIANT) in operator tests (/= is not transitive so all three pairs must be checked) * Fix NAG/ifx CI failure: remove @before from ESMF_TestMethod test module @before in a module with @test(type=ESMF_TestMethod) causes pFUnit to generate code that passes the before-routine via ESMF_TestMethod's private TREE component, which NAG and ifx both reject. Move load_field_dictionary call into setup() instead, which is called by every ESMF_TestMethod test. This matches the pattern used in Test_VectorBasisKind.pf. --------- Co-authored-by: Matt Thompson <matthew.thompson@nasa.gov>
1 parent 2ae5e73 commit 4723810

23 files changed

Lines changed: 2154 additions & 46 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
/@ESMA_env/
66
/ESMA_env/
77
/ESMA_env@/
8+
/@GEOS_FieldDictionary/
9+
/GEOS_FieldDictionary/
10+
/GEOS_FieldDictionary@/
811
/.mepo/
912
*.py.bak
1013
CMakeUserPresets.json

CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,23 @@ install (
275275
configure_file(BUILD_INFO.rc.in BUILD_INFO.rc @ONLY)
276276
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/BUILD_INFO.rc DESTINATION etc)
277277

278+
# Install the canonical GEOS field dictionary so experiment scripts can
279+
# copy/link it as field_dictionary.yaml in the run directory.
280+
# mepo can clone subrepos in three styles (no prefix, @ prefix, @ suffix).
281+
set(FIELD_DICTIONARY_DIRS
282+
GEOS_FieldDictionary
283+
@GEOS_FieldDictionary
284+
GEOS_FieldDictionary@
285+
)
286+
foreach(dir IN LISTS FIELD_DICTIONARY_DIRS)
287+
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/geos_field_dictionary.yaml)
288+
install(
289+
FILES ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/geos_field_dictionary.yaml
290+
DESTINATION etc
291+
)
292+
endif()
293+
endforeach()
294+
278295
# https://www.scivision.dev/cmake-auto-gitignore-build-dir/
279296
# --- auto-ignore build directory
280297
if(NOT EXISTS ${PROJECT_BINARY_DIR}/.gitignore)

components.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ ecbuild:
1818
local: ./ESMA_cmake/ecbuild
1919
remote: ../ecbuild.git
2020
tag: geos/v3.13.1
21+
22+
GEOS_FieldDictionary:
23+
local: ./GEOS_FieldDictionary
24+
remote: ../GEOS_FieldDictionary.git
25+
tag: v0.2.1
26+
develop: main

0 commit comments

Comments
 (0)