diff --git a/docs/source/known-bugs.rst b/docs/source/known-bugs.rst index 50ed355..2f5fea7 100644 --- a/docs/source/known-bugs.rst +++ b/docs/source/known-bugs.rst @@ -6,6 +6,36 @@ This page lists known bugs in :program:`qfyaml`. See the `Github issues `_ page for updates on their status. +************* +Version 0.3.2 +************* + +Error parsing categories +======================== + +We discovered an error parsing this YAML file, where the +:code:`wet_deposition` tag is more than 2 indentation levels behind +behind the previous line. + +.. code-block:: yaml + + operations: + transport: + passive_species: + CH3ITracer: + long_name: Methyl_iodide + mol_wt_in_g: 142.0 + lifetime_in_s: 4.32e5 + default_bkg_conc_in_vv: 1.0e-20 + wet_deposition: + activate: true + +This has now been fixed in qfyaml 0.3.3. + +NOTE: For best results with qfyaml, we recommend formatting YAML files +so that they contain a consistent indentation level throughout the +file (i.e. such as 2 or 4 spaces). Editors such as Emacs can do this easily. + ************* Version 0.3.0 ************* diff --git a/src/qfyaml_mod.F90 b/src/qfyaml_mod.F90 index 1fca047..f8d6942 100644 --- a/src/qfyaml_mod.F90 +++ b/src/qfyaml_mod.F90 @@ -40,6 +40,7 @@ MODULE QFYAML_Mod PUBLIC :: QFYAML_CleanUp PUBLIC :: QFYAML_Get PUBLIC :: QFYAML_Check + PUBLIC :: QFYAML_FindDepth PUBLIC :: QFYAML_FindNextHigher PUBLIC :: QFYAML_Init PUBLIC :: QFYAML_Merge @@ -741,7 +742,8 @@ SUBROUTINE Parse_Line( yml, yml_anchored, set_by, & ! SAVEd variables LOGICAL, SAVE :: is_list_var = .FALSE. INTEGER, SAVE :: last_pos = 0 - INTEGER, SAVE :: cat_pos(20) = 0 + INTEGER, SAVE :: indent = 0 + INTEGER, SAVE :: cat_pos(QFYAML_MaxStack) = 0 INTEGER, SAVE :: cat_index = 0 CHARACTER(LEN=QFYAML_NamLen), SAVE :: cat_stack(QFYAML_MaxStack) = "" @@ -805,15 +807,19 @@ SUBROUTINE Parse_Line( yml, yml_anchored, set_by, & ! If this category starts further along the line than the last ! category, then increment index and add its position to the stack. IF ( pos > last_pos ) THEN + indent = last_pos - pos cat_index = cat_index + 1 cat_pos(cat_index) = pos ENDIF ! If this category starts earlier along the line than the last ! category, then decrement index and add its position to the stack. - ! last category, then this + ! NOTE: This algorithm will work best if we assume a constant + ! indentation level. Best to use an editor such as emacs + ! to enforce a consistent indentation throughout the file. IF ( pos < last_pos ) THEN - cat_index = cat_index - 1 + indent = last_pos - pos + cat_index = cat_index - ( indent / 2 ) cat_pos(cat_index) = pos ENDIF @@ -821,7 +827,7 @@ SUBROUTINE Parse_Line( yml, yml_anchored, set_by, & ! character of the line, then set index to 1 and store its ! starting position in the first element of the stack. IF ( cat_index <= 0 .or. pos == 1 ) THEN - cat_index = 1 + cat_index = 1 cat_pos(cat_index) = pos ENDIF @@ -927,9 +933,9 @@ SUBROUTINE Parse_Line( yml, yml_anchored, set_by, & category = cat_stack(C) IF ( C > 1 ) THEN DO CC = C-1, 1, -1 - category = TRIM( cat_stack(CC) ) // & - QFYAML_Category_Separator // & - TRIM( category ) + category = TRIM( cat_stack(CC) ) // & + QFYAML_Category_Separator // & + TRIM( category ) ENDDO ENDIF EXIT @@ -941,16 +947,15 @@ SUBROUTINE Parse_Line( yml, yml_anchored, set_by, & category = cat_stack( MAX( C-1, 1 ) ) IF ( C-1 > 1 ) THEN DO CC = C-2, 1, -1 - category = TRIM( cat_stack(CC) ) // & - QFYAML_Category_Separator // & - TRIM( category ) + category = TRIM( cat_stack(CC) ) // & + QFYAML_Category_Separator // & + TRIM( category ) ENDDO ENDIF EXIT ENDIF ENDDO - ! Test if the variable is a YAML anchor IF ( var_name == "<<" ) THEN @@ -1498,6 +1503,51 @@ END SUBROUTINE QFYAML_check ! ! !IROUTINE: QFYAML_FindNextHigher ! +! !DESCRIPTION: For a given category or variable name, returns its depth +! (i.e. indentation level). This is equal to the number of separator +! strings. +!\\ +!\\ +! !INTERFACE: +! + FUNCTION QFYAML_FindDepth( name ) RESULT( depth ) +! +! !INPUT PARAMETERS: +! + CHARACTER(LEN=*), INTENT(IN) :: name +! +! RETURN VALUE: +! + INTEGER :: depth +!EOP +!------------------------------------------------------------------------------ +!BOC +! +! !LOCAL VARIABLES: +! + INTEGER :: ix, c + + ! Keep searching for all category separators + ! until there aren't any more. + depth = 1 + c = LEN_TRIM( name ) + DO + ix = INDEX( name(1:c), QFYAML_Category_Separator, back=.TRUE. ) + IF ( ix <= 1 ) EXIT + depth = depth + 1 + c = ix - 1 + ENDDO + + END FUNCTION QFYAML_FindDepth +!EOC +!------------------------------------------------------------------------------ +! QFYAML: Bob Yantosca | yantosca@seas.harvard.edu | Apr 2020 +! Based on existing package https://github.com/jannisteunissen/config_fortran +!------------------------------------------------------------------------------ +!BOP +! +! !IROUTINE: QFYAML_FindNextHigher +! ! !DESCRIPTION: Finds variables that are one category depth higher than ! a given target string (trg_str). Returns the number of variables that ! match this criteria (n_matches), as well as the variables themselves diff --git a/test/qfyaml.yml b/test/qfyaml.yml index c4f07c3..ee9d92d 100644 --- a/test/qfyaml.yml +++ b/test/qfyaml.yml @@ -1,5 +1,5 @@ --- -#### input.yml - Input for test_qfyaml.F90 +#### qfyaml.yml - Input for test_qfyaml.F90 #### Test going back & forth between levels weather: @@ -10,7 +10,18 @@ weather: units: K pressure: 1013.25 -#### Test parsing different types of input +operations: + transport: + passive_species: + CH3ITracer: + long_name: Methyl_iodide + mol_wt_in_g: 142.0 + lifetime_in_s: 4.32e5 + default_bkg_conc_in_vv: 1.0e-20 + wet_deposition: + activate: true + +##### Test parsing different types of input author: age: 29 fav_reals: [1.0, 2.0] @@ -47,3 +58,5 @@ filename: another_file author_name: first: Homer full: Homer J. Simpson + + diff --git a/test/test_qfyaml.F90 b/test/test_qfyaml.F90 index b58cded..ee7c8dd 100644 --- a/test/test_qfyaml.F90 +++ b/test/test_qfyaml.F90 @@ -65,63 +65,68 @@ PROGRAM Test_QFYAML key = "author%age" v_int = -999 - CALL QFYAML_Add_Get( yml, key, v_int, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_int, "", RC ) WRITE( 6, "(a32, "" : "", i7)") ADJUSTL(key), v_int key = "author%fav_reals" ALLOCATE( a_real(2) ) a_real = -999.0_yp - CALL QFYAML_Add_Get( yml, key, a_real, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), a_real, "", RC ) WRITE( 6, "(a32, "" : "", 2f7.2)") ADJUSTL(key), a_real DEALLOCATE( a_real ) key = "author%more_reals" ALLOCATE( a_real(4) ) a_real = -999.0_yp - CALL QFYAML_Add_Get( yml, key, a_real, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), a_real, "", RC ) WRITE( 6, "(a32, "" : "", 4f11.6)") ADJUSTL(key), a_real DEALLOCATE( a_real ) key = "author%lots_of_work" v_bool = .FALSE. - CALL QFYAML_Add_Get( yml, key, v_bool, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_bool, "", RC ) WRITE( 6, "(a32, "" : "", l7)") ADJUSTL(key), v_bool key = "author_name%first" v_str = "" - CALL QFYAML_Add_Get( yml, key, v_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_str, "", RC ) WRITE( 6, "(a32, "" : "", a)") ADJUSTL(key), TRIM(v_str) key = "author_name%full" v_str = "" - CALL QFYAML_Add_Get( yml, key, v_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_str, "", RC ) WRITE( 6, "(a32, "" : "", a)") ADJUSTL(key), TRIM(v_str) key = "filename" v_str = "" - CALL QFYAML_Add_Get( yml, key, v_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_str, "", RC ) WRITE( 6, "(a32, "" : "", a)") ADJUSTL(key), TRIM(v_str) key = "weather%humidity" v_real = -999.0_yp - CALL QFYAML_Add_Get( yml, key, v_real, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_real, "", RC ) WRITE( 6, "(a32, "" : "", f13.6)") ADJUSTL(key), v_real key = "weather%temperature%daily" v_real = -999.0_yp - CALL QFYAML_Add_Get( yml, key, v_real, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_real, "", RC ) WRITE( 6, "(a32, "" : "", f13.6)") ADJUSTL(key), v_real key = "weather%temperature%weekly%units" v_real = -999.0_yp - CALL QFYAML_Add_Get( yml, key, v_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_str, "", RC ) WRITE( 6, "(a32, "" : "", a)") ADJUSTL(key), TRIM(v_str) key = "weather%pressure" v_real = -999.0_yp - CALL QFYAML_Add_Get( yml, key, v_real, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), v_real, "", RC ) WRITE( 6, "(a32, "" : "", f13.6)") ADJUSTL(key), v_real + key = "operations%wet_deposition%activate" + v_bool = .FALSE. + CALL QFYAML_Add_Get( yml, TRIM( key ), v_bool, "", RC ) + WRITE( 6, "(a32, "" : "", l7)") ADJUSTL(key), v_bool + WRITE( 6, '(/, a)' ) '### FIND NEXT-HIGHER VARIABLES IN "weather"' CALL QFYAML_FindNextHigher( yml, "weather%", match_ct, match_vars ) @@ -135,7 +140,7 @@ PROGRAM Test_QFYAML key = "fruits" ALLOCATE( a_str(3) ) a_str = "" - CALL QFYAML_Add_Get( yml, key, a_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), a_str, "", RC ) WRITE( 6, "(a)" ) TRIM(key) DO N = 1, SIZE( a_str ) print*, N, TRIM( a_str(N) ) @@ -146,7 +151,7 @@ PROGRAM Test_QFYAML key = "more_fruits%p_fruits" ALLOCATE( a_str(4) ) a_str = "" - CALL QFYAML_Add_Get( yml, key, a_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), a_str, "", RC ) WRITE( 6, "(a)" ) TRIM(key) DO N = 1, SIZE( a_str ) print*, N, TRIM( a_str(N) ) @@ -158,7 +163,7 @@ PROGRAM Test_QFYAML key = "even_more_fruits%exotic_fruits%hard_to_find" ALLOCATE( a_str(5) ) a_str = "" - CALL QFYAML_Add_Get( yml, key, a_str, "", RC ) + CALL QFYAML_Add_Get( yml, TRIM( key ), a_str, "", RC ) WRITE( 6, "(a)" ) TRIM(key) DO N = 1, SIZE( a_str ) print*, N, TRIM( a_str(N) ) diff --git a/test/test_species_database.F90 b/test/test_species_database.F90 index 4a54cfa..f5fa5d5 100644 --- a/test/test_species_database.F90 +++ b/test/test_species_database.F90 @@ -33,7 +33,7 @@ PROGRAM Test_Species_Database ! Strings CHARACTER(LEN=14) :: tag - CHARACTER(LEN=14) :: spc + CHARACTER(LEN=31) :: spc CHARACTER(LEN=255) :: v_str CHARACTER(LEN=255) :: key CHARACTER(LEN=255) :: fileName @@ -44,7 +44,7 @@ PROGRAM Test_Species_Database ! String arrays CHARACTER(LEN=17) :: tags(46) - CHARACTER(LEN=14) :: species(11) + CHARACTER(LEN=31) :: species(11) ! Objects TYPE(QFYAML_t) :: yml @@ -77,8 +77,8 @@ PROGRAM Test_Species_Database RC = QFYAML_SUCCESS mw_g = MISSING_INT - species(1) = "ACTA" - species(2) = "ALD2" + species(1) = "CO" + species(2) = "COAnthroEmis25dayTracer" species(3) = "ALK4" species(4) = "ASOA1" species(5) = "ASOA2"