NOAA-EMC / RDASApp

Regional DAS
GNU Lesser General Public License v2.1
1 stars 7 forks source link

Incorporate Mesonet DA into JEDI for RRFS #80

Open delippi opened 3 weeks ago

delippi commented 3 weeks ago

The UFO in JEDI is the component that not only computes model-simulated observations, but also houses filters and methods for observation QC, ob errors, and bias correction. The GSI observer is the equivalent. Many forward operators for various observations have been developed for the UFO. These operators can be utilized in RDAS. However these operators still must be tested for RDAS. The steps for transition by observation platform are as follows:

  1. Establish IODA processing
  2. Establish operator in UFO
  3. Establish YAML input file
  4. Validate with test assimilation experiments
  5. Create ctest, if necessary

Mesonet data is bufr obtype=188/288 (and also 195/295 but not sure if that data is/will be used).

Edit: A link to my GSI fork/branch based on Andrew and Emily's ufo_geovals branch. I added some extra geovals for output. https://github.com/delippi/GSI/tree/feature/ufo_geovals_rdas

delippi commented 3 weeks ago

I've finished hofx validation for mesonet airTemperature. In this example, I'm using a version of GSI (from Andrew) that writes out GSI geovals and a modified version of the ufo-vertInterp code (based on a branch from Dan who modified the gnssro operator to be able to read in GSI geovals using the fv3jedi executable--I did the same thing but for the vertInterp operator). I also had to write a short python script to update my GSI-geovals files to have saturation_specific_humidity and surface_geometric_height. The former was calculated from Rogers and Yau eq 2.19. The latter just needed to grab only the lowest model level for surface_geometric_height from the geometric_height field. The following is the result for airTemperature hofx validation. More work will be done on other variables. Then once all hofx validation is done I will move to observation error and other QC checks. gsi_hofx_vs_jedi_hofx_MSONET_hofxs_airTemperature_2022052619_mesonet_airTemperature

If the GSI-geovals are not read in this is the following result. I'm thinking that this could be considered as "close enough" when NOT using GSI-geovals. I believe the differences are due to how GSI and JEDI compute geovals (i.e., 2D interpolation using 3 vs 4 points for example). I have an issue looking into this. gsi_hofx_vs_jedi_hofx_MSONET_hofxs_airTemperature_2022052619_mesonet_airTemperature

delippi commented 3 weeks ago

Finished the hofx validation for remaining variables (using vertInterp) specificHumidity, windEastward, and windNorthward. Once again, these results are using GSI-geovals feed into vertInterp operator and differences will still remain due to how GSI and JEDI calculate geovals.

gsi_hofx_vs_jedi_hofx_MSONET_hofxs_specificHumidity_2022052619_mesonet_specificHumidity

gsi_hofx_vs_jedi_hofx_MSONET_hofxs_uv_2022052619_mesonet_windEastward

gsi_hofx_vs_jedi_hofx_MSONET_hofxs_uv_2022052619_mesonet_windNorthward

delippi commented 2 weeks ago

I've started looking into ob error inflation. Here is the result from a full mesonet observation test. The right plot shows the GSI vs JEDI final oberror ratios. There are clear differences that need to be understood. The hofx plot on the left shows one-to-one comparison since the geovals are fed directly into ufo's vertical interpolation operator. The final ob errors do not match because the ufo obfilters such as ObsFunction/ObsErrorFactorPressureCheck is not also being fed the geovals from GSI. I checked this via another single-ob test using a different observation than what I used before. fv3jedi_vs_gsi_validation_188_airTemperature

Here is the ob I chose and the resulting initial ob error comparison.

fv3jedi_vs_gsi_validation_188_airTemperature_single

gsi_errf=39.8781
jedi_errf=34.974

Here are the corresponding GSI-geovals for this single ob.

netcdf sfc_tsen_geoval_2022052619 {
dimensions:
        nlocs = 1 ;
        nlevs = 60 ;
        ninterfaces = 61 ;
        Station_ID_maxstrlen = 8 ;
        Observation_Class_maxstrlen = 7 ;
variables:
        float latitude(nlocs) ;
        float longitude(nlocs) ;
        float time(nlocs) ;
        float surface_pressure(nlocs) ;
        float air_pressure(nlocs, nlevs) ;
        float air_pressure_levels(nlocs, ninterfaces) ;
        float air_temperature(nlocs, nlevs) ;
        float virtual_temperature(nlocs, nlevs) ;
        float specific_humidity(nlocs, nlevs) ;
        float eastward_wind(nlocs, nlevs) ;
        float northward_wind(nlocs, nlevs) ;
        float geopotential_height(nlocs, nlevs) ;
        float geometric_height(nlocs, nlevs) ;
        float surface_geometric_height(nlocs) ;
        float saturation_specific_humidity(nlocs, nlevs) ;

// global attributes:
                :date_time = 2022052619 ;
data:

 latitude = 29.15 ;

 longitude = 256.47 ;

 time = 0 ;

 surface_pressure = 91893.05 ;

 air_pressure =
  755.7465, 1868.049, 2983.181, 4102.358, 5226.591, 6361.438, 7513.978, 
    8686.738, 9889.828, 11128.3, 12402.16, 13726.57, 15106.59, 16562.43, 
    18134.53, 19868.4, 21799.41, 23937.67, 26313.52, 28925.12, 31707.87, 
    34570.54, 37438.94, 40291.35, 43141.63, 45998.63, 48856.96, 51705.39, 
    54530.09, 57326.04, 60082.09, 62777.85, 65405.58, 67935.79, 70321.66, 
    72533.61, 74554.91, 76385.96, 78018.52, 79461.47, 80736.48, 81847.89, 
    82821.54, 83662, 84386.59, 85038.16, 85638.18, 86208.16, 86752.34, 
    87270.73, 87767.65, 88247.36, 88709.94, 89159.62, 89600.63, 90033.09, 
    90456.94, 90872.23, 91282.16, 91689.8 ;

 air_pressure_levels =
  200, 1311.493, 2424.604, 3541.759, 4662.958, 5790.223, 6932.653, 8095.303, 
    9278.173, 10501.48, 11755.12, 13049.2, 14403.94, 15809.23, 17315.62, 
    18953.44, 20783.35, 22815.46, 25059.88, 27567.16, 30283.08, 33132.66, 
    36008.42, 38869.46, 41713.24, 44570.03, 47427.24, 50286.68, 53124.12, 
    55936.06, 58716.03, 61448.16, 64107.56, 66703.62, 69167.98, 71475.37, 
    73591.88, 75517.96, 77253.98, 78783.09, 80139.88, 81333.11, 82362.7, 
    83280.41, 84043.62, 84729.59, 85346.77, 85929.63, 86486.71, 87017.99, 
    87523.51, 88011.82, 88482.95, 88936.98, 89382.3, 89819.02, 90247.2, 
    90666.71, 91077.78, 91486.59, 91893.05 ;

 air_temperature =
  235.6375, 224.4905, 218.1675, 213.6949, 213.5903, 207.6426, 206.0895, 
    206.2977, 203.9101, 204.1167, 205.3741, 207.642, 209.8925, 212.0992, 
    214.099, 216.5952, 220.5284, 224.5905, 228.8093, 233.3199, 237.7421, 
    242.3809, 246.8677, 251.4358, 255.7671, 259.6447, 262.6363, 265.6216, 
    268.7856, 271.9664, 274.8885, 277.6014, 280.2744, 282.9365, 285.4703, 
    287.8022, 289.9375, 291.8065, 293.3411, 294.455, 295.3679, 296.2541, 
    296.9786, 297.6199, 298.2021, 298.7821, 299.3857, 299.9604, 300.5107, 
    301.0414, 301.5591, 302.0586, 302.5493, 303.0456, 303.5226, 304.0048, 
    304.5028, 304.9882, 305.4874, 306.0442 ;

 specific_humidity =
  2.752339e-06, 1.904394e-06, 1.394001e-06, 1.379674e-06, 1.379306e-06, 
    1.377589e-06, 1.40844e-06, 1.582917e-06, 2.397518e-06, 2.761124e-06, 
    3.063641e-06, 4.004941e-06, 4.907784e-06, 8.561648e-06, 1.400903e-05, 
    1.929839e-05, 2.306499e-05, 3.07411e-05, 4.232386e-05, 7.573712e-05, 
    0.0001071723, 0.0001724478, 0.0002271507, 0.0003030314, 0.0004094222, 
    0.000541823, 0.0007843238, 0.001047134, 0.001294734, 0.00150681, 
    0.001731838, 0.001989752, 0.002196813, 0.002296577, 0.002383559, 
    0.002425554, 0.002479532, 0.002559666, 0.002792936, 0.003182035, 
    0.003523703, 0.003710348, 0.00390177, 0.004104795, 0.00441022, 
    0.004679783, 0.004720944, 0.004746933, 0.004768888, 0.004791364, 
    0.004813664, 0.00483504, 0.00485517, 0.004874029, 0.00489172, 
    0.004908095, 0.004923194, 0.004936983, 0.004949572, 0.004962991 ;

 eastward_wind =
  -4.228357, -6.544117, -12.40301, -9.521055, -5.278649, 1.093383, 
    -0.5375162, 1.721064, 10.03384, 10.48232, 10.83364, 10.69437, 10.9804, 
    13.03079, 13.88336, 14.23912, 12.26383, 11.20725, 10.65507, 12.56708, 
    14.49977, 14.68172, 14.83068, 14.79433, 13.5991, 12.19977, 10.78136, 
    9.972265, 9.590845, 8.495372, 6.849806, 4.988925, 3.511991, 2.999388, 
    3.143361, 3.677207, 4.232866, 4.222813, 3.626519, 2.296938, 1.214826, 
    -0.06948268, -0.4343772, -0.8267059, -1.111862, -1.280351, -1.400046, 
    -1.501276, -1.597076, -1.693949, -1.787644, -1.875156, -1.954497, 
    -2.024871, -2.085754, -2.135643, -2.173452, -2.197542, -2.205784, 
    -2.191741 ;

 northward_wind =
  4.067732, 3.094453, -0.6086304, -0.1323414, -4.160838, 3.078696, -1.005045, 
    -3.330433, -1.419531, 0.4915086, 0.8171092, 1.352675, 1.592034, 1.097219, 
    -0.9191248, -2.726938, -3.137551, -2.894401, -3.198701, -3.485875, 
    -3.607549, -3.811813, -4.590881, -5.260763, -6.225089, -6.378666, 
    -5.142704, -5.012124, -5.243576, -4.273788, -2.753191, -1.622213, 
    -0.8835961, -0.4733567, -0.291191, -0.1172846, 0.2097148, 0.4525892, 
    0.6018959, 0.7836246, 0.8502474, 0.7726977, 0.7246647, 0.6420889, 
    0.5781096, 0.5359891, 0.5019259, 0.4698849, 0.4376185, 0.4039004, 
    0.3701546, 0.337393, 0.3064236, 0.2775157, 0.2508291, 0.2268822, 
    0.2059942, 0.1886475, 0.1752818, 0.1653261 ;

 geopotential_height =
  32284.62, 26192.84, 23161.41, 21148.63, 19634.61, 18423.68, 17415.81, 
    16540.8, 15762.37, 15058.07, 14408.79, 13795.71, 13210.52, 12642.5, 
    12077.08, 11501.71, 10908.54, 10299.19, 9671.478, 9031.684, 8398.622, 
    7791.421, 7220.816, 6685.446, 6178.142, 5694.484, 5233.662, 4795.486, 
    4379.327, 3983.411, 3607.365, 3252.2, 2917.101, 2603.931, 2316.487, 
    2056.362, 1823.697, 1616.88, 1435.549, 1277.67, 1140.03, 1021.432, 
    918.5604, 830.5157, 755.1499, 687.7866, 626.0804, 567.7474, 512.3081, 
    459.7226, 409.521, 361.2435, 314.8624, 269.9324, 226.0159, 183.0937, 
    141.157, 100.1908, 59.8703, 19.88624 ;

 geometric_height =
  32507.72, 26348.37, 23287.75, 21257.21, 19730.69, 18510.29, 17494.88, 
    16613.6, 15829.79, 15120.79, 14467.32, 13850.4, 13261.67, 12690.31, 
    12121.66, 11543.12, 10946.79, 10334.31, 9703.49, 9060.663, 8424.727, 
    7814.888, 7241.911, 6704.41, 6195.17, 5709.742, 5247.304, 4807.652, 
    4390.149, 3993.005, 3615.839, 3259.656, 2923.635, 2609.633, 2321.455, 
    2060.687, 1827.466, 1620.168, 1438.428, 1280.2, 1142.262, 1023.414, 
    920.3271, 832.1015, 756.5828, 689.0844, 627.2556, 568.8079, 513.2605, 
    460.5734, 410.2756, 361.9065, 315.4379, 270.4239, 226.4259, 183.4246, 
    141.4111, 100.3705, 59.97732, 19.92166 ;

 surface_geometric_height = 19.92166 ;

 saturation_specific_humidity =
  0.02014038, 0.002466431, 0.0007363904, 0.0003075175, 0.0002381839, 
    8.956026e-05, 6.128983e-05, 5.456117e-05, 3.432543e-05, 3.14106e-05, 
    3.362379e-05, 4.150242e-05, 5.099787e-05, 6.208447e-05, 7.322237e-05, 
    9.125465e-05, 0.0001336413, 0.0001946684, 0.0002826511, 0.0004149006, 
    0.000592959, 0.0008536862, 0.001197073, 0.001672704, 0.002265279, 
    0.002928171, 0.003505401, 0.004184011, 0.005049723, 0.006083087, 
    0.007171612, 0.008316158, 0.00960482, 0.01107564, 0.01266047, 0.01428834, 
    0.0159377, 0.01750122, 0.01885235, 0.01982511, 0.02063227, 0.02147753, 
    0.02217406, 0.02281329, 0.02341854, 0.02405554, 0.02475703, 0.02544167, 
    0.02611313, 0.02677693, 0.02744124, 0.02809555, 0.02875415, 0.02943988, 
    0.03010899, 0.03080327, 0.03154269, 0.03227707, 0.0330539, 0.03395744 ;

and here are the JEDI-geovals:

netcdf msonet_geovals_rrfs_2022052619_0000 {
dimensions:
        nlocs = 1 ;
        air_temperature_nval = 60 ;
        air_pressure_nval = 60 ;
        geopotential_height_nval = 60 ;
        saturation_specific_humidity_nval = 60 ;
        surface_pressure_nval = 1 ;
        surface_geometric_height_nval = 1 ;
variables:
        float air_temperature(nlocs, air_temperature_nval) ;
        float air_pressure(nlocs, air_pressure_nval) ;
        float geopotential_height(nlocs, geopotential_height_nval) ;
        float saturation_specific_humidity(nlocs, saturation_specific_humidity_nval) ;
        float surface_pressure(nlocs, surface_pressure_nval) ;
        float surface_geometric_height(nlocs, surface_geometric_height_nval) ;
data:

 air_temperature =
  235.6378, 224.4909, 218.1918, 213.7335, 213.6359, 207.7357, 206.1277, 
    206.3607, 203.9762, 204.1579, 205.3943, 207.6636, 209.9156, 212.1392, 
    214.1317, 216.6082, 220.5322, 224.6023, 228.813, 233.3283, 237.7528, 
    242.3918, 246.8813, 251.4621, 255.8076, 259.6915, 262.6952, 265.6933, 
    268.8654, 272.048, 274.9818, 277.7316, 280.4175, 283.087, 285.6224, 
    287.9653, 290.1075, 291.9906, 293.5446, 294.6653, 295.5721, 296.4574, 
    297.18, 297.8099, 298.3815, 298.9362, 299.5392, 300.1133, 300.6627, 
    301.1918, 301.7127, 302.2111, 302.7009, 303.2041, 303.6779, 304.1591, 
    304.6568, 305.1499, 305.6472, 306.2061 ;

 air_pressure =
  700.493, 1847.963, 2970.646, 4093.206, 5219.338, 6355.322, 7508.618, 
    8681.94, 9885.321, 11124.1, 12398.14, 13722.59, 15102.7, 16558.35, 
    18130.13, 19863.38, 21793.77, 23931.41, 26306.41, 28917.7, 31701.63, 
    34568.21, 37443.17, 40304.14, 43164.25, 46032.07, 48901.81, 51762.08, 
    54598.77, 57406.79, 60174.9, 62882.62, 65522.05, 68063.74, 70460.52, 
    72682.67, 74713.31, 76552.84, 78192.98, 79642.59, 80923.48, 82040.03, 
    83018.16, 83862.51, 84590.41, 85244.96, 85847.72, 86420.3, 86966.96, 
    87487.73, 87986.91, 88468.83, 88933.52, 89385.25, 89828.29, 90262.72, 
    90688.51, 91105.7, 91517.52, 91927.03 ;

 geopotential_height =
  33616.32, 27083.71, 24008.19, 21981.85, 20461.66, 19247.24, 18237.16, 
    17360.63, 16581.07, 15875.85, 15225.9, 14612.32, 14026.65, 13458.26, 
    12892.5, 12316.91, 11723.53, 11113.95, 10486.03, 9845.886, 9212.146, 
    8603.776, 8031.633, 7494.526, 6985.426, 6499.972, 6037.421, 5597.591, 
    5179.88, 4782.513, 4405.11, 4048.662, 3712.362, 3398.068, 3109.607, 
    2848.569, 2615.098, 2407.571, 2225.616, 2067.198, 1929.095, 1810.105, 
    1706.9, 1618.571, 1542.97, 1475.401, 1413.509, 1355.001, 1299.396, 
    1246.655, 1196.305, 1147.885, 1101.367, 1056.305, 1012.26, 969.2122, 
    927.1532, 886.0674, 845.6292, 805.5286 ;

 saturation_specific_humidity =
  0.02165116, 0.002489244, 0.0007417696, 0.0003102094, 0.0002402886, 
    9.107734e-05, 6.185361e-05, 5.524064e-05, 3.477191e-05, 3.170728e-05, 
    3.383402e-05, 4.175642e-05, 5.129251e-05, 6.253931e-05, 7.364197e-05, 
    9.148115e-05, 0.00013366, 0.0001946587, 0.000282107, 0.0004140031, 
    0.0005914937, 0.00085131, 0.001193862, 0.001670138, 0.002264834, 
    0.002929631, 0.003511235, 0.004195979, 0.005068264, 0.006107367, 
    0.007207532, 0.008380654, 0.009688043, 0.01117592, 0.01277464, 
    0.01442475, 0.01609402, 0.01768549, 0.01907377, 0.02006679, 0.02087597, 
    0.02172871, 0.02242968, 0.02306024, 0.02365805, 0.02426763, 0.02497263, 
    0.02566025, 0.02633366, 0.02699843, 0.0276711, 0.02832667, 0.02898693, 
    0.02968713, 0.03035376, 0.03104919, 0.03179094, 0.03254208, 0.03331833, 
    0.03422884 ;

 surface_pressure =
  92131.25 ;

 surface_geometric_height =
  785.5793 ;
}

and the obs_pressure = 93670 so the ob is located below the ground.

I noticed two things in ObsErrorFactorPressureCheck.cc:

  1. it was using model_pressure_sfc[iloc]=92131.25 which happens to be the JEDI-geoval surface pressure value. So I hardcoded it as model_pressure_sfc[iloc]=91893.05; to be the GSI-geoval.
  2. and prsl[0][iloc]=91927 and prsl[1][iloc]=91517.5 which are also the JEDI-geoval air_pressure values. So I hardcoded them as prsl[0][iloc]=91689.8; and prsl[1][iloc]=91282.16; to be the GSI-geovals (remember reverse order here). The other levels don't matter here since the ob is actually located below the model bottom.

Now the oberrors match exactly (within rounding error at least) for this case. I've attached the final ob error comparison figure below. I'm not sure how how have feed obserror function read the GSI-geovals directly in order to do a full ob test. Perhaps it is good enough to do no more than a few single ob cases where we know the ob error differences are large and hard code the GSI-geovals.

fv3jedi_vs_gsi_validation_188_airTemperature_after

TLDR; differences in how GSI and JEDI create geovals are the root cause of the differences found in both hofx and ob error validation. When the GSI-geovals are fed into JEDI the results match exactly. JEDI's method is NOT necessarily wrong it is just different. The JEDI results need not necessarily replicate GSI, but if they do not we must understand the differences as shown here.

delippi commented 1 week ago

Doing the same thing for q and uv; hard coding the GSI-geovals in ObsFunction/ObsErrorFactorPressureCheck for a single ob test.

Here are the results when using JEDI-geovals: fv3jedi_vs_gsi_validation_188_specificHumidity fv3jedi_vs_gsi_validation_288_windEastward

Here are the results when using GSI-geovals: fv3jedi_vs_gsi_validation_188_specificHumidity fv3jedi_vs_gsi_validation_288_windEastward

delippi commented 1 week ago

Working on hofx and oberror for the last variable type: stationPressure. This one uses Identity operator instead of vertInterp like the other variables. I'm looking at the single ob result from the case with initial large mismatch in ob errors for other variable types. Here is the initial result when looking at omf, hofx, oberror, and analysis increments. The large hofx and thus large omf results in the non-zero increments. The GSI-hofx is from GsiHofXBc.

fv3jedi_vs_gsi_increment_288_stationPressure

We can plot the GsiHofX (i.e., non-bias corrected) and we have the following result. We can ignore that the increment is still zero because that isn't the hofx used in the GSI analysis, however, the hofx shown in the bottom left more closely aligns with the result from JEDI. The differences at this point I'm going to attribute likely due to differences in geovals (see #54). The operator used here is the Identity so the hofx are essentially just geovals. Now I need to figure out how to include the bias correction that GSI is using.

fv3jedi_vs_gsi_increment_288_stationPressure

delippi commented 1 week ago

Actually, mesonet (188) stationPressure shouldn't use Identity operator. It should use:

       obs operator:
         name: SfcPCorrected
         da_psfc_scheme: GSI
         geovar_sfc_geomz: surface_geopotential_height
         geovar_geomz: geopotential_height
       linear obs operator:
         name: Identity

Here is the result when changing the obs operator. There are still differences, but again, I think those are simply due to differences in how GSI and JEDI compute geovals. I'm uncertain why there is zero increment in GSI though. fv3jedi_vs_gsi_increment_288_stationPressure