diff --git a/parm/jedivar.yaml b/parm/jedivar.yaml index aed420c49..b706ac59a 100644 --- a/parm/jedivar.yaml +++ b/parm/jedivar.yaml @@ -194,6 +194,7 @@ cost function: threshold: 12.0 action: name: reject + - *POLY # yamllint disable-line rule:anchors - obs space: name: adpsfc_t181 distribution: @@ -267,6 +268,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Duplicate Check # - filter: Temporal Thinning # filter variables: @@ -543,6 +546,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Duplicate Check # - filter: Temporal Thinning # filter variables: @@ -817,6 +822,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Duplicate Check - filter: Temporal Thinning filter variables: @@ -1095,6 +1102,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Duplicate Check # - filter: Temporal Thinning # filter variables: @@ -1370,6 +1379,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Duplicate Check # - filter: Temporal Thinning # filter variables: @@ -1650,6 +1661,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -1924,6 +1937,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -2195,6 +2210,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -2473,6 +2490,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -2790,6 +2809,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -3100,6 +3121,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -3413,6 +3436,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -3687,6 +3712,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -3961,6 +3988,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -4235,6 +4264,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -4505,6 +4536,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -4782,6 +4815,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -5092,6 +5127,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -5399,6 +5436,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -5673,6 +5712,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -5950,6 +5991,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -6257,6 +6300,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -6531,6 +6576,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -6805,6 +6852,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -7079,6 +7128,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -7353,6 +7404,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -7630,6 +7683,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -7940,6 +7995,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -8250,6 +8307,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -8560,6 +8619,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -8840,6 +8901,8 @@ cost function: name: assign error error parameter: 0.01 + - *POLY # yamllint disable-line rule:anchors + # Terrain Height Discrepancy Check - filter: Difference Check reference: MetaData/stationElevation @@ -8941,6 +9004,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -9215,6 +9280,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -9482,6 +9549,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -10337,6 +10406,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -10688,6 +10759,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -10962,6 +11035,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -11236,6 +11311,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -11511,6 +11588,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -11785,6 +11864,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -12059,6 +12140,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -12334,6 +12417,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -12604,6 +12689,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online regional domain check - filter: Bounds Check filter variables: @@ -12890,6 +12977,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -13206,6 +13295,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -13523,6 +13614,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -13839,6 +13932,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check filter variables: @@ -14195,6 +14290,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check udescriptor: "online_domain_check" @@ -14602,6 +14699,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check udescriptor: "online_domain_check" @@ -15009,6 +15108,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check udescriptor: "online_domain_check" @@ -15382,6 +15483,8 @@ cost function: # action: # name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check udescriptor: "online_domain_check" @@ -15780,6 +15883,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Online domain check - filter: Bounds Check udescriptor: "online_domain_check" @@ -16162,6 +16267,8 @@ cost function: action: name: reduce obs space + - *POLY # yamllint disable-line rule:anchors + # Duplicate Check - filter: Temporal Thinning udescriptor: "duplicate_check" @@ -16557,6 +16664,8 @@ cost function: - name: Thinning initial value: false force reinitialization: false + # domain boundary check + - *POLY # yamllint disable-line rule:anchors obs post filters: #Thinning - filter: Gaussian Thinning @@ -17013,7 +17122,8 @@ cost function: - name: UseflagCheck initial value: false force reinitialization: false - + # domain boundary check + - *POLY # yamllint disable-line rule:anchors obs post filters: # Step 0-B: Calculate derived variables # Calculate CLW retrieved from observation @@ -17602,7 +17712,8 @@ cost function: - name: UseflagCheck initial value: false force reinitialization: false - + # domain boundary check + - *POLY # yamllint disable-line rule:anchors obs post filters: # Step 0-B: Calculate derived variables # Calculate CLW retrieved from observation @@ -18170,6 +18281,8 @@ cost function: maxvalue: 65. action: name: reduce obs space + # domain boundary check + - *POLY # yamllint disable-line rule:anchors # Data Thinning - filter: Gaussian Thinning filter variables: @@ -18678,6 +18791,8 @@ cost function: maxvalue: 65. action: name: reduce obs space + # Domain boundary check + - *POLY # yamllint disable-line rule:anchors # Data Thinning - filter: Gaussian Thinning filter variables: @@ -19204,6 +19319,8 @@ cost function: - name: UseflagCheck initial value: false force reinitialization: false + # Domain boundary check + - *POLY # yamllint disable-line rule:anchors obs post filters: # Step 0-B: Calculate derived variables @@ -19759,6 +19876,8 @@ cost function: - name: Thinning initial value: false force reinitialization: false + # Domain boundary check + - *POLY # yamllint disable-line rule:anchors obs post filters: #Thinning - filter: Gaussian Thinning @@ -20182,6 +20301,8 @@ cost function: - name: Thinning initial value: false force reinitialization: false + # Domain boundary check + - *POLY # yamllint disable-line rule:anchors obs post filters: #Thinning - filter: Gaussian Thinning @@ -20642,6 +20763,11 @@ cost function: initial value: false force reinitialization: false + # -------------------------------------- + # Step "one half:" Domain boundary check + # -------------------------------------- + - *POLY # yamllint disable-line rule:anchors + # ---------------------------------------------------------------- # Step 1 : Create Derived Variables for radiane to BT conversion # Assign channel wavenumbers in m-1 @@ -21190,6 +21316,11 @@ cost function: initial value: false force reinitialization: false + # -------------------------------------- + # Step "one half:" Domain boundary check + # -------------------------------------- + - *POLY # yamllint disable-line rule:anchors + # ---------------------------------------------------------------- # Step 1 : Create Derived Variables for radiane to BT conversion # Assign channel wavenumbers in m-1 diff --git a/scripts/exrrfs_ioda_bufr.sh b/scripts/exrrfs_ioda_bufr.sh index 24d390b4e..c37ad0fe9 100755 --- a/scripts/exrrfs_ioda_bufr.sh +++ b/scripts/exrrfs_ioda_bufr.sh @@ -121,26 +121,14 @@ ln -sf abibufr "rap.t${cyc}z.gsrcsr.tm00.bufr_d" cp "rap.t${cyc}z.abi_g16.tm00.nc" "ioda_abi_g16.nc" cp "rap.t${cyc}z.abi_g18.tm00.nc" "ioda_abi_g18.nc" -# run offline IODA tools -${cpreq} "${USHrrfs}"/offline_domain_check.py . -${cpreq} "${USHrrfs}"/offline_domain_check_satrad.py . ${cpreq} "${USHrrfs}"/offline_ioda_tweak.py . ${cpreq} "${USHrrfs}"/offline_vad_thinning.py . for ioda_file in ioda*nc; do - grid_file="${FIXrrfs}/${MESH_NAME}/${MESH_NAME}.static.nc" - #if [[ "${ioda_file}" == *abi* || "${ioda_file}" == *atms* || "${ioda_file}" == *cris* ]]; then - if [[ "${ioda_file}" == *abi* ]]; then - echo " ${ioda_file} ioda file detected: running offline_domain_check_satrad.py" - ./offline_domain_check_satrad.py -o "${ioda_file}" -g "${grid_file}" -s 0.005 - base_name=$(basename "$ioda_file" .nc) - mv "${base_name}_dc.nc" "${base_name}.nc" - elif [[ "${ioda_file}" == *atms* || "${ioda_file}" == *cris* ]]; then - echo " ${ioda_file} ioda file detected: temporarily skipping offline domain check" + if [[ "${ioda_file}" == *abi* || "${ioda_file}" == *atms* || "${ioda_file}" == *cris* ]]; then + echo " ${ioda_file} ioda tweak is skipped for abi, atms, and cris" else - ./offline_domain_check.py -o "${ioda_file}" -g "${grid_file}" -s 0.005 - base_name=$(basename "$ioda_file" .nc) - mv "${base_name}_dc.nc" "${base_name}.nc" + echo " ${ioda_file} running ioda tweak" ./offline_ioda_tweak.py -o "${ioda_file}" base_name=$(basename "$ioda_file" .nc) mv "${base_name}_llp.nc" "${base_name}.nc" diff --git a/scripts/exrrfs_jedivar.sh b/scripts/exrrfs_jedivar.sh index 7b79b7271..8eff02a84 100755 --- a/scripts/exrrfs_jedivar.sh +++ b/scripts/exrrfs_jedivar.sh @@ -136,10 +136,16 @@ case ${YAML_GEN_METHOD:-1} in ;; esac +if ( grep -E '\*POLY' jedivar.yaml > /dev/null ) ; then + cp jedivar.yaml no_polygon_jedivar.yaml + "${USHrrfs}/yamlify_domain_edge.py" -g "invariant.nc" -i '' > polygon.yaml + cat polygon.yaml no_polygon_jedivar.yaml > jedivar.yaml +fi + if [[ ${start_type} == "warm" ]] || [[ ${start_type} == "cold" && ${COLDSTART_CYCS_DO_DA^^} == "TRUE" ]]; then # run mpasjedi_variational.x - #export OOPS_TRACE=1 - #export OOPS_DEBUG=1 + export OOPS_TRACE=1 + export OOPS_DEBUG=1 export OMP_NUM_THREADS=1 source prep_step diff --git a/sorc/_workaround_/PolygonCheck/CMakeLists.txt b/sorc/_workaround_/PolygonCheck/CMakeLists.txt new file mode 100644 index 000000000..993bcb480 --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/CMakeLists.txt @@ -0,0 +1,406 @@ +# (C) Copyright 2017-2018 UCAR. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + +set ( filters_files + BackgroundCheck.cc + BackgroundCheck.h + BayesianBackgroundQCFlags.cc + BayesianBackgroundQCFlags.h + BayesianBackgroundCheck.cc + BayesianBackgroundCheck.h + BlackList.cc + BlackList.h + ConventionalProfileProcessing.cc + ConventionalProfileProcessing.h + ConventionalProfileProcessingParameters.h + CopyFlagsFromExtendedToOriginalSpace.cc + CopyFlagsFromExtendedToOriginalSpace.h + CreateDiagnosticFlags.cc + CreateDiagnosticFlags.h + DiagnosticFlag.h + DifferenceCheck.cc + DifferenceCheck.h + EnsembleStatistics.cc + EnsembleStatistics.h + FilterBase.cc + FilterBase.h + FilterParametersBase.cc + FilterParametersBase.h + FilterUtils.cc + FilterUtils.h + FinalCheck.cc + FinalCheck.h + GenericFilterParameters.h + GeoVaLsWriter.cc + GeoVaLsWriter.h + getScalarOrFilterData.cc + getScalarOrFilterData.h + HistoryCheck.cc + HistoryCheck.h + HistoryCheckParameters.h + ImpactHeightCheck.cc + ImpactHeightCheck.h + ObsBoundsCheck.cc + ObsBoundsCheck.h + ObsProcessorBase.cc + ObsProcessorBase.h + MetOfficeBuddyCheck.cc + MetOfficeBuddyCheck.h + MetOfficeBuddyCheckParameters.h + MetOfficeBuddyCollector.cc + MetOfficeBuddyCollector.h + MetOfficeBuddyCollectorV1.cc + MetOfficeBuddyCollectorV1.h + MetOfficeBuddyCollectorV2.cc + MetOfficeBuddyCollectorV2.h + MetOfficeBuddyPair.h + MetOfficeBuddyPairFinder.cc + MetOfficeBuddyPairFinder.h + MetOfficeDuplicateCheck.cc + MetOfficeDuplicateCheck.h + MetOfficePressureConsistencyCheck.cc + MetOfficePressureConsistencyCheck.h + ModelBestFitPressure.cc + ModelBestFitPressure.h + ModelObThreshold.cc + ModelObThreshold.h + MWCLWCheck.cc + MWCLWCheck.h + ObsDiagnosticsWriter.cc + ObsDiagnosticsWriter.h + ObsDomainCheck.cc + ObsDomainCheck.h + ObsDerivativeCheck.cc + ObsDerivativeCheck.h + ObsDomainErrCheck.cc + ObsDomainErrCheck.h + ObsFilterData.cc + ObsFilterData.h + ObsPolygonCheck.cc + ObsPolygonCheck.h + ObsRefractivityGradientCheck.h + ObsRefractivityGradientCheck.cc + ParameterSubstitution.cc + ParameterSubstitution.h + PreQC.cc + PreQC.h + ProbabilityGrossErrorWholeReport.cc + ProbabilityGrossErrorWholeReport.h + ProcessAMVQI.cc + ProcessAMVQI.h + QCflags.h + QCmanager.cc + QCmanager.h + PerformAction.cc + PerformAction.h + ProfileAverageObsToModLevels.cc + ProfileAverageObsToModLevels.h + AverageObsToGeoValLevels.cc + AverageObsToGeoValLevels.h + ProfileBackgroundCheck.cc + ProfileBackgroundCheck.h + ProfileFewObsCheck.cc + ProfileFewObsCheck.h + ProfileMaxDifferenceCheck.cc + ProfileMaxDifferenceCheck.h + ProfileUnFlagObsCheck.cc + ProfileUnFlagObsCheck.h + SatName.h + SatName.cc + SatwindInversionCorrection.cc + SatwindInversionCorrection.h + SpikeAndStepCheck.cc + SpikeAndStepCheck.h + StuckCheck.cc + StuckCheck.h + StuckCheckParameters.h + SuperOb.h + SuperOb.cc + SuperRefractionCheckImpactParameter.h + SuperRefractionCheckImpactParameter.cc + SuperRefractionCheckNBAM.h + SuperRefractionCheckNBAM.cc + obsfunctions/DrawObsErrorFromFile.cc + obsfunctions/DrawObsErrorFromFile.h + obsfunctions/DrawValueFromFile.cc + obsfunctions/DrawValueFromFile.h + Thinning.cc + Thinning.h + TemporalThinning.cc + TemporalThinning.h + TemporalThinningParameters.h + TrackCheck.cc + TrackCheck.h + TrackCheckParameters.h + TrackCheckShip.cc + TrackCheckShip.h + TrackCheckShipDiagnostics.h + TrackCheckShipParameters.h + TrackCheckUtils.cc + TrackCheckUtils.h + TrackCheckUtilsParameters.cc + TrackCheckUtilsParameters.h + Variable.cc + Variable.h + VariableTransforms.cc + VariableTransforms.h + VariableTransformParametersBase.h + Variables.cc + Variables.h + VariableAssignment.cc + VariableAssignment.h + AcceptList.cc + AcceptList.h + Gaussian_Thinning.cc + Gaussian_Thinning.h + GaussianThinningParameters.cc + GaussianThinningParameters.h + PoissonDiskThinning.cc + PoissonDiskThinning.h + PoissonDiskThinningParameters.cc + PoissonDiskThinningParameters.h + processWhere.cc + processWhere.h + ObsAccessor.cc + ObsAccessor.h + PrintFilterData.cc + PrintFilterData.h + actions/AssignError.cc + actions/AssignError.h + actions/AcceptObs.cc + actions/AcceptObs.h + actions/FilterAction.cc + actions/FilterAction.h + actions/FilterActionBase.cc + actions/FilterActionBase.h + actions/FlagOriginalAndAveragedProfiles.cc + actions/FlagOriginalAndAveragedProfiles.h + actions/InflateError.cc + actions/InflateError.h + actions/PassivateObs.cc + actions/PassivateObs.h + actions/ReduceObsSpace.cc + actions/ReduceObsSpace.h + actions/RejectObs.cc + actions/RejectObs.h + actions/ROobserrInflation.cc + actions/ROobserrInflation.h + actions/SetFlag.cc + actions/SetFlag.h + actions/SetFlagBit.cc + actions/SetFlagBit.h + obsfunctions/AircraftBiasCorrectionTerm.cc + obsfunctions/AircraftBiasCorrectionTerm.h + obsfunctions/AverageTemperatureBelow.cc + obsfunctions/AverageTemperatureBelow.h + obsfunctions/BennartzScatIndex.cc + obsfunctions/BennartzScatIndex.h + obsfunctions/ChannelUseflagCheckRad.cc + obsfunctions/ChannelUseflagCheckRad.h + obsfunctions/CLWMatchIndexMW.cc + obsfunctions/CLWMatchIndexMW.h + obsfunctions/CLWRetMW.cc + obsfunctions/CLWRetMW.h + obsfunctions/TotalColumnVaporGuess.cc + obsfunctions/TotalColumnVaporGuess.h + obsfunctions/CLWRetMW_SSMIS.cc + obsfunctions/CLWRetMW_SSMIS.h + obsfunctions/CLWRetSymmetricMW.cc + obsfunctions/CLWRetSymmetricMW.h + obsfunctions/Conditional.cc + obsfunctions/Conditional.h + obsfunctions/AssignValueEqualChannels.cc + obsfunctions/AssignValueEqualChannels.h + obsfunctions/SetSeaIceEmiss.cc + obsfunctions/SetSeaIceEmiss.h + obsfunctions/SetSurfaceType.cc + obsfunctions/SetSurfaceType.h + obsfunctions/SIRetMW.cc + obsfunctions/SIRetMW.h + obsfunctions/SIRetSymmetricMW.cc + obsfunctions/SIRetSymmetricMW.h + obsfunctions/Emissivity_Diff_GMI.cc + obsfunctions/Emissivity_Diff_GMI.h + obsfunctions/HydrometeorCheckAMSUA.cc + obsfunctions/HydrometeorCheckAMSUA.h + obsfunctions/HydrometeorCheckATMS.cc + obsfunctions/HydrometeorCheckATMS.h + obsfunctions/HydrometeorCheckAMSUAclr.cc + obsfunctions/HydrometeorCheckAMSUAclr.h + obsfunctions/ImpactHeight.cc + obsfunctions/ImpactHeight.h + obsfunctions/InterChannelConsistencyCheck.cc + obsfunctions/InterChannelConsistencyCheck.h + obsfunctions/LiquidWaterPathGuess.cc + obsfunctions/LiquidWaterPathGuess.h + obsfunctions/BgdDepartureAnomaly.cc + obsfunctions/BgdDepartureAnomaly.h + obsfunctions/ObsErrorModelHumidity.cc + obsfunctions/ObsErrorModelHumidity.h + obsfunctions/ObsErrorModelStepwiseLinear.cc + obsfunctions/ObsErrorModelStepwiseLinear.h + obsfunctions/ObsErrorModelRamp.cc + obsfunctions/ObsErrorModelRamp.h + obsfunctions/ObsErrorModelQuad.cc + obsfunctions/ObsErrorModelQuad.h + obsfunctions/ObsFunction.cc + obsfunctions/ObsFunction.h + obsfunctions/ObsFunctionArithmetic.cc + obsfunctions/ObsFunctionArithmetic.h + obsfunctions/ObsFunctionBase.cc + obsfunctions/ObsFunctionBase.h + obsfunctions/CloudCostFunction.cc + obsfunctions/CloudCostFunction.h + obsfunctions/CloudDetectMinResidualAVHRR.cc + obsfunctions/CloudDetectMinResidualAVHRR.h + obsfunctions/CloudDetectMinResidualIR.cc + obsfunctions/CloudDetectMinResidualIR.h + obsfunctions/CloudFirstGuessMinimumResidual.cc + obsfunctions/CloudFirstGuessMinimumResidual.h + obsfunctions/MetOfficeAllSkyErrorModel.cc + obsfunctions/MetOfficeAllSkyErrorModel.h + obsfunctions/ModelHeightAdjustedWindVectorComponent.cc + obsfunctions/ModelHeightAdjustedWindVectorComponent.h + obsfunctions/ModelHeightAdjustedAirTemperature.cc + obsfunctions/ModelHeightAdjustedAirTemperature.h + obsfunctions/ModelHeightAdjustedRelativeHumidity.cc + obsfunctions/ModelHeightAdjustedRelativeHumidity.h + obsfunctions/ModelHeightAdjustedMarineWind.cc + obsfunctions/ModelHeightAdjustedMarineWind.h + obsfunctions/MPIRank.cc + obsfunctions/MPIRank.h + obsfunctions/ObsErrorBoundConventional.cc + obsfunctions/ObsErrorBoundConventional.h + obsfunctions/ObsErrorBoundIR.cc + obsfunctions/ObsErrorBoundIR.h + obsfunctions/ObsErrorBoundMW.cc + obsfunctions/ObsErrorBoundMW.h + obsfunctions/ObsErrorSatSpecHumidity.cc + obsfunctions/ObsErrorSatSpecHumidity.h + obsfunctions/ObsErrorFactorDuplicateCheck.cc + obsfunctions/ObsErrorFactorDuplicateCheck.h + obsfunctions/ObsErrorFactorPressureCheck.cc + obsfunctions/ObsErrorFactorPressureCheck.h + obsfunctions/ObsErrorFactorSituDependMW.cc + obsfunctions/ObsErrorFactorSituDependMW.h + obsfunctions/ObsErrorFactorSurfJacobianRad.cc + obsfunctions/ObsErrorFactorSurfJacobianRad.h + obsfunctions/ObsErrorFactorLatRad.cc + obsfunctions/ObsErrorFactorLatRad.h + obsfunctions/ObsErrorFactorQuotient.cc + obsfunctions/ObsErrorFactorQuotient.h + obsfunctions/ObsErrorFactorTopoRad.cc + obsfunctions/ObsErrorFactorTopoRad.h + obsfunctions/ObsErrorFactorTransmitTopRad.cc + obsfunctions/ObsErrorFactorTransmitTopRad.h + obsfunctions/ObsErrorFactorWavenumIR.cc + obsfunctions/ObsErrorFactorWavenumIR.h + obsfunctions/ObsErrorFactorSfcPressure.cc + obsfunctions/ObsErrorFactorSfcPressure.h + obsfunctions/ObsErrorFactorConventional.cc + obsfunctions/ObsErrorFactorConventional.h + obsfunctions/PotentialTemperatureFromTemperature.cc + obsfunctions/PotentialTemperatureFromTemperature.h + obsfunctions/NearSSTRetCheckIR.cc + obsfunctions/NearSSTRetCheckIR.h + obsfunctions/ObsFunctionElementMultiply.cc + obsfunctions/ObsFunctionElementMultiply.h + obsfunctions/ObsFunctionExponential.cc + obsfunctions/ObsFunctionExponential.h + obsfunctions/ObsFunctionScattering.cc + obsfunctions/ObsFunctionScattering.h + obsfunctions/ObsFunctionSelectStatistic.cc + obsfunctions/ObsFunctionSelectStatistic.h + obsfunctions/ObsFunctionStringManipulation.cc + obsfunctions/ObsFunctionStringManipulation.h + obsfunctions/ObsFunctionVelocity.cc + obsfunctions/ObsFunctionVelocity.h + obsfunctions/ObsFunctionVisibilityDiagnostic.cc + obsfunctions/ObsFunctionVisibilityDiagnostic.h + obsfunctions/OceanPressureToDepth.cc + obsfunctions/OceanPressureToDepth.h + obsfunctions/OrbitAngle.cc + obsfunctions/OrbitAngle.h + obsfunctions/SatwindIndivErrors.cc + obsfunctions/SatwindIndivErrors.h + obsfunctions/SatWindsLNVDCheck.cc + obsfunctions/SatWindsLNVDCheck.h + obsfunctions/WindsSPDBCheck.cc + obsfunctions/WindsSPDBCheck.h + obsfunctions/SatWindsErrnormCheck.cc + obsfunctions/SatWindsErrnormCheck.h + obsfunctions/ScatWindsAmbiguityCheck.cc + obsfunctions/ScatWindsAmbiguityCheck.h + obsfunctions/SCATRetMW.cc + obsfunctions/SCATRetMW.h + obsfunctions/SymmCldImpactIR.cc + obsfunctions/SymmCldImpactIR.h + obsfunctions/SolarZenith.cc + obsfunctions/SolarZenith.h + obsfunctions/StableLayersCloudTopPressure.cc + obsfunctions/StableLayersCloudTopPressure.h + obsfunctions/SunGlintAngle.cc + obsfunctions/SunGlintAngle.h + obsfunctions/SurfTypeCheckRad.cc + obsfunctions/SurfTypeCheckRad.h + obsfunctions/GeoCloudCreateCloudColumn.cc + obsfunctions/GeoCloudCreateCloudColumn.h + obsfunctions/SurfaceCloudCreateCloudColumn.cc + obsfunctions/SurfaceCloudCreateCloudColumn.h + obsfunctions/SurfaceCloudModelLevelCBH.cc + obsfunctions/SurfaceCloudModelLevelCBH.h + obsfunctions/TropopauseEstimate.cc + obsfunctions/TropopauseEstimate.h + obsfunctions/TropopauseHeight.cc + obsfunctions/TropopauseHeight.h + obsfunctions/WindDirAngleDiff.cc + obsfunctions/WindDirAngleDiff.h + obsfunctions/WindUVfromObsSpdHofxDir.cc + obsfunctions/WindUVfromObsSpdHofxDir.h + obsfunctions/LAMDomainCheck/LAMDomainCheck.cc + obsfunctions/LAMDomainCheck/LAMDomainCheck.h + obsfunctions/LAMDomainCheck/LAMDomainCheck.interface.h + obsfunctions/LAMDomainCheck/LAMDomainCheck.interface.F90 + obsfunctions/LAMDomainCheck/esg_grid_mod.F90 + obsfunctions/ProfileAverageObsPressure.cc + obsfunctions/ProfileAverageObsPressure.h + obsfunctions/ProfileLevelCount.cc + obsfunctions/ProfileLevelCount.h + obsfunctions/DateTimeOffset.cc + obsfunctions/DateTimeOffset.h + obsfunctions/FillAveragedProfileData.cc + obsfunctions/FillAveragedProfileData.h + obsfunctions/MetOfficeRelativeHumidityCorrection.cc + obsfunctions/MetOfficeRelativeHumidityCorrection.h + obsfunctions/RadarScanEdgeFlag.cc + obsfunctions/RadarScanEdgeFlag.h + obsfunctions/RecordNumberToObsSpace.cc + obsfunctions/RecordNumberToObsSpace.h + obsfunctions/ModelLevelIndex.cc + obsfunctions/ModelLevelIndex.h +) + +if( ${gsw_FOUND} ) + list( APPEND filters_files OceanVerticalStabilityCheck.cc + OceanVerticalStabilityCheck.h ) +endif( ${gsw_FOUND} ) + +if( ${rttov_FOUND} ) + add_subdirectory( rttovonedvarcheck ) + list( APPEND filters_files ${rttovonedvarcheck_src_files} ) +endif( ${rttov_FOUND} ) + +add_subdirectory( gnssroonedvarcheck ) +list( APPEND filters_files ${gnssroonedvarcheck_src_files} ) + +add_subdirectory( refractivityonedvarcheck ) +list( APPEND filters_files ${refractivityonedvarcheck_src_files} ) + +PREPEND( _p_filters_files "filters" ${filters_files} ) + +set ( filters_src_files + ${_p_filters_files} + PARENT_SCOPE +) diff --git a/sorc/_workaround_/PolygonCheck/FIXME_DELETE_THIS_DIRECTORY b/sorc/_workaround_/PolygonCheck/FIXME_DELETE_THIS_DIRECTORY new file mode 100644 index 000000000..01ad7d253 --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/FIXME_DELETE_THIS_DIRECTORY @@ -0,0 +1,6 @@ +# This directory must be deleted before the PR is merged. +# It serves only to copy the JEDI UFO changes into this PR for testing. + +# Files come from here: + +# - https://github.com/JCSDA/ufo/pull/78 diff --git a/sorc/_workaround_/PolygonCheck/ObsPolygonCheck.cc b/sorc/_workaround_/PolygonCheck/ObsPolygonCheck.cc new file mode 100644 index 000000000..7ca130d75 --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/ObsPolygonCheck.cc @@ -0,0 +1,137 @@ +/* + * CC0 - No Copyright (Public Domain) + * + * The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. + * + * You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. See Other Information below. + * + * Other Information + * In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights. + * + * The person who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law. + * + * When using or citing the work, you should not imply endorsement by the author or the affirmer. + */ + +#include "ufo/filters/ObsPolygonCheck.h" + +#include +#include +#include +#include + +#include +#include "ioda/ObsSpace.h" +#include "oops/util/Logger.h" + +namespace ufo { + +// ----------------------------------------------------------------------------- + +ObsPolygonCheck::ObsPolygonCheck(ioda::ObsSpace & obsdb, const Parameters_ & parameters, + std::shared_ptr > flags, + std::shared_ptr > obserr) + : FilterBase(obsdb, parameters, flags, obserr), parameters_(parameters) +{ + oops::Log::trace() << "ObsPolygonCheck constructor" << std::endl; +} + +// ----------------------------------------------------------------------------- + +ObsPolygonCheck::~ObsPolygonCheck() { + oops::Log::trace() << "ObsPolygonCheck destructor" << std::endl; +} + +// ----------------------------------------------------------------------------- + +void ObsPolygonCheck::applyFilter(const std::vector &apply, + const Variables & filtervars, + std::vector> & flagged) const { + oops::Log::trace() << "ObsPolygonCheck applyFilter start" << std::endl; + + namespace bg = boost::geometry; + + // point_t = a boost::geometry point as a longitude-latitude pair in degrees + using point_t = bg::model::point>; + + // polygon_t = a closed polygon of those points + using polygon_t = bg::model::polygon; + + // Get from the parameters a point within the polygon. + const point_t insidePoint(parameters_.inside_point_longitude.value(), + parameters_.inside_point_latitude.value()); + + // Assemble a polygon from the list of longitudes and latitudes. + polygon_t poly; + const auto &vertex_latitudes = parameters_.vertex_latitudes.value(); + const auto &vertex_longitudes = parameters_.vertex_longitudes.value(); + const size_t nlon = vertex_longitudes.size(); + const size_t nlat = vertex_latitudes.size(); + if (nlon != nlat) { + std::ostringstream what; + what << "Mismatch between vertex longitude count (" << nlon + << ") and vertex latitude count (" << nlat << ")."; + throw ObsPolygonLatLonSizeMismatch(what.str(), Here()); + } + poly.outer().reserve(nlon); + for (size_t i = 0; i < nlon; i++) + poly.outer().emplace_back(vertex_longitudes[i], vertex_latitudes[i]); + + // Ask boost::geometry to correct common problems in the polygon definition. + // As of boost 1.91, the only practical effect is to close open rings. + // It will also correct the vertex ordering, but vertex ordering on a + // sphere is ignored. + bg::correct(poly); + + // Check for polygons that the boost::geometry library doesn't know how to handle. + if (std::string reason; !bg::is_valid(poly, reason)) { + std::ostringstream what; + what << "ObsPolygonCheck: boost::geometry does not like your polygon (\"" << reason << "\")"; + throw ObsPolygonIsInvalid(what.str(), Here()); + } + + // Get the observation locations. + std::vector lats, lons; + obsdb_.get_db("MetaData", "latitude", lats); + obsdb_.get_db("MetaData", "longitude", lons); + + // Figure out which side is the inside by checking a point that is known to be inside. + // As of version 1.91, boost::geometry ignores the clockwise vs. counterclockwise when + // deciding which side of a polygon is the inside in spherical geometry. Hence, + // we need this "inside point" to determine which side is the inside. + const bool useThisSide = bg::within(insidePoint, poly); + + // Find all points that are on the opposite side from the "inside point" + const size_t nlocs = obsdb_.nlocs(); + std::vector notInside(nlocs, true); + size_t applyCount = 0; + size_t insideCount = 0; + for (size_t iloc = 0; iloc < nlocs; iloc++) { + if (apply[iloc]) { + applyCount++; + const bool inside = useThisSide == bg::within(point_t(lons[iloc], lats[iloc]), poly); + notInside[iloc] = !inside; + if (inside) + insideCount++; + } + } + + for (auto &vec : flagged) + for (size_t iloc = 0; iloc < nlocs; iloc++) + if (apply[iloc]) + vec[iloc] = notInside[iloc]; + + oops::Log::trace() << "ObsPolygonCheck applyFilter complete (kept " << insideCount + << " of " << applyCount << " locations discarding " + << (applyCount - insideCount) << ")" << std::endl; +} + +// ----------------------------------------------------------------------------- + +void ObsPolygonCheck::print(std::ostream & os) const { + os << "ObsPolygonCheck: config = " << parameters_ << std::endl; +} + +// ----------------------------------------------------------------------------- + +} // namespace ufo diff --git a/sorc/_workaround_/PolygonCheck/ObsPolygonCheck.h b/sorc/_workaround_/PolygonCheck/ObsPolygonCheck.h new file mode 100644 index 000000000..b78409e2f --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/ObsPolygonCheck.h @@ -0,0 +1,111 @@ +/* + * CC0 - No Copyright (Public Domain) + * + * The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. + * + * You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. See Other Information below. + * + * Other Information + * In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights. + * + * The person who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law. + * + * When using or citing the work, you should not imply endorsement by the author or the affirmer. + */ + +#ifndef UFO_FILTERS_OBSPOLYGONCHECK_H_ +#define UFO_FILTERS_OBSPOLYGONCHECK_H_ + +#include +#include +#include +#include +#include + +#include +#include "oops/util/ObjectCounter.h" +#include "ufo/filters/FilterBase.h" +#include "ufo/filters/QCflags.h" + +namespace ioda { + template class ObsDataVector; + class ObsSpace; +} + +namespace ufo { + +class ObsPolygonCheckParameters : public FilterParametersBase { + OOPS_CONCRETE_PARAMETERS(ObsPolygonCheckParameters, FilterParametersBase) + + public: + oops::RequiredParameter> vertex_longitudes { + "vertex longitudes", + "Longitudes of vertices of the polygon.", + this}; + oops::RequiredParameter> vertex_latitudes { + "vertex latitudes", + "Latitudes of vertices of the polygon.", + this}; + oops::RequiredParameter inside_point_longitude { + "inside point longitude", + "Longitude of a point inside the polygon (used to determine which side is inside).", + this}; + oops::RequiredParameter inside_point_latitude { + "inside point latitude", + "Latitude of a point inside the polygon (used to determine which side is inside).", + this}; +}; + +/// ObsPolygonLatLonSizeMismatch: thrown when the parameters vertex_longitudes +/// and vertex_latitudes have different lengths. + +class ObsPolygonLatLonSizeMismatch: public eckit::BadValue { + public: + explicit ObsPolygonLatLonSizeMismatch(const std::string &message, + const eckit::CodeLocation &location = {}): + eckit::BadValue(message, location) + {} +}; + +/// ObsPolygonIsInvalid: thrown when boost::geometry::is_valid doesn't like a polygon. + +class ObsPolygonIsInvalid: public eckit::BadValue { + public: + explicit ObsPolygonIsInvalid(const std::string &message, + const eckit::CodeLocation &location = {}): + eckit::BadValue(message, location) + {} +}; + +/// PolygonCheck: flags all obs that aren't inside a specified +/// polygon; uses the boost::geometry library. The boost::geometry +/// library doesn't know which side is the inside of the polygon when +/// using spherical geometry. Hence, the caller must provide an +/// "inside point." Points on the other side of the polygon are flagged. + +class ObsPolygonCheck : public FilterBase, + private util::ObjectCounter { + public: + /// The type of parameters accepted by the constructor of this filter. + /// This typedef is used by the FilterFactory. + typedef ObsPolygonCheckParameters Parameters_; + + static const std::string classname() {return "ufo::ObsPolygonCheck";} + + ObsPolygonCheck(ioda::ObsSpace &, const Parameters_ &, + std::shared_ptr >, + std::shared_ptr >); + ~ObsPolygonCheck(); + + private: + void print(std::ostream &) const override; + void applyFilter(const std::vector &, const Variables &, + std::vector> &) const override; + int qcFlag() const override {return QCflags::domain;} + + Parameters_ parameters_; +}; + +} // namespace ufo + +#endif // UFO_FILTERS_OBSPOLYGONCHECK_H_ diff --git a/sorc/_workaround_/PolygonCheck/filtersCMakeLists.txt b/sorc/_workaround_/PolygonCheck/filtersCMakeLists.txt new file mode 100644 index 000000000..3f4561f87 --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/filtersCMakeLists.txt @@ -0,0 +1,1329 @@ +# (C) Copyright 2022 UCAR. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + +# Unit tests for filters + +add_subdirectory(actions) +add_subdirectory(obsfunctions) + + +ufo_add_test( NAME test_ufo_amsua_seaice_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_seaice_qc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_assign_error_using_where + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/assign_error_using_where.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_ensemblestatistics + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_EnsembleObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/ensemblestatistics.yaml" + MPI 8 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_ensemblestatistics_channels + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_EnsembleObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/ensemblestatistics_channels.yaml" + MPI 8 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_filter_stage + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/filter_stage.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_filter_stage_mpi + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/filter_stage.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrobendmetoffice_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobendmetoffice_qc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrobendmetoffice_qc_profile + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobendmetoffice_qc_profile.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrobendmetoffice_obserror + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobendmetoffice_obserror.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrorefmetoffice_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrorefmetoffice_qc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrobndnbam_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobndnbam_qc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrobndnbam_qc_geos + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobndnbam_qc_geos.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssrobndnbam_qc_action_obserr_inflation + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobndnbam_qc_action_obserr_inflation.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_gnssro_obs_error + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssro_obs_error.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) + +# +ufo_add_test( NAME test_ufo_gnssro_super_refraction_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssro_super_refraction_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_metar_qc_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/metar_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_obserror_assign_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestObsErrorAssign.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/obserror_assign_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_obsfilterdata + TIER 1 + ECBUILD + SOURCES ../../../mains/TestObsFilterData.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/obsfilterdata.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_ompsnp_npp_qc_L127 + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/ompsnp_npp_qc_L127.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data_MPI2 + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data_MPI3 + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data.yaml" + MPI 3 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data_inefficient_distribution + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data_inefficient_distribution.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data_MPI2_rank0 + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data_MPI2_rank0.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data_time_window_selection + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data_time_window_selection.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_print_filter_data_time_window_selection_MPI2 + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/print_filter_data_time_window_selection.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_processwhere + TIER 1 + ECBUILD + SOURCES ../../../mains/TestProcessWhere.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/processwhere.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_acceptlist + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_acceptlist.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_backgroundcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_backgroundcheck.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_backgroundcheck_ensemblestatistics + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_EnsembleObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_backgroundcheck_ensemblestatistics.yaml" + MPI 8 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_bayesianbackgroundqcflags + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_bayesianbackgroundqcflags.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_bayesian_background_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_bayesian_background_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_boundscheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_boundscheck.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_creatediagnosticflags + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_creatediagnosticflags.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_function_copy_flags_from_extended_to_original_space + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_copy_flags_from_ext_to_orig_space.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_defer_to_post + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_defer_to_post.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_derivative_dpdt + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_derivative_dpdt.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_derivative_dxdt + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_derivative_dxdt.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_differencecheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_differencecheck.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_finalcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_finalcheck.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_mean + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_mean.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_mean_error + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_mean_error.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_median + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_median.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_ops + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_ops.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_records_are_single_obs + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_records_are_single_obs.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_satrad + TIER 1 + ECBUILD + SOURCES ../../../mains/TestGaussianThinning.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_satrad.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_gauss_thinning_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestGaussianThinning.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_gauss_thinning_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_grosserrorwholereport + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_grosserrorwholereport.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_historycheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_historycheck.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_historycheck_mpi + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_historycheck.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_historycheck_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestHistoryCheck.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_historycheck_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_met_office_buddy_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_met_office_buddy_check.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_met_office_buddy_check_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestMetOfficeBuddyCheck.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_met_office_buddy_check_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_met_office_buddy_pair_finder + TIER 1 + ECBUILD + SOURCES ../../../mains/TestMetOfficeBuddyPairFinder.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_met_office_buddy_pair_finder.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_met_office_pressure_consistency_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_met_office_pressure_consistency_check.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_modelbestfitpressure + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_modelbestfitpressure.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_modelobthreshold + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_modelobthreshold.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_multichannel_thinning + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_multichannel_thinning.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_oceancolor_preqc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_oceancolor_preqc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +if( ${gsw_FOUND} ) + ufo_add_test( NAME test_ufo_qc_ocean_vertical_stability_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_ocean_vertical_stability_check.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +endif( ${gsw_FOUND} ) +# +ufo_add_test( NAME test_ufo_qc_poisson_disk_thinning + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_poisson_disk_thinning.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_poisson_disk_thinning_parallel + TIER 1 + ECBUILD + SOURCES ../../../mains/TestParallelPoissonDiskThinning.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_poisson_disk_thinning_parallel.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_poisson_disk_thinning_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestPoissonDiskThinning.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_poisson_disk_thinning_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_met_office_duplicate_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_met_office_duplicate_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_met_office_duplicate_check_parallel + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_met_office_duplicate_check.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_preqc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_preqc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_preqc_halo + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_preqc_halo.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_processamvqi + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_processamvqi.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_average_obs_to_mod_levels + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_profile_average_obs_to_mod_levels.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_profile_background_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_profile_background_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_profile_fewobs_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_profile_fewobs_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_profile_unflagobs_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_profile_unflagobs_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_spike_and_step_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_spike_and_step_check.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_stuckcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_stuckcheck.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_stuckcheck_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestStuckCheck.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_stuckcheck_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_thinning + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_thinning.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_temporal_thinning + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_temporal_thinning.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_temporal_thinning_records_are_single_obs + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_temporal_thinning_records_are_single_obs.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_temporal_thinning_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestTemporalThinning.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_temporal_thinning_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_trackcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_trackcheck.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_trackcheckship + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_trackcheckship.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_trackcheck_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestTrackCheck.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_trackcheck_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_trackcheckship_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestTrackCheckShip.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_trackcheckship_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_trackcheckship_mainloop_unittests + TIER 1 + ECBUILD + SOURCES ../../../mains/TestTrackCheckShipMainLoop.cc + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_trackcheckship_mainloop_unittests.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_qc_variableassignment + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/qc_variableassignment.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_satname + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/satname.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_satwind_inversion_correction + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/satwind_inversion_correction.yaml" + MPI 2 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_iasi_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/iasi_qc.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_superob + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/superob.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_superob_4PE + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/superob.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_superob_radar + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/superob_radar.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_superob_radar_4PE + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/superob_radar.yaml" + MPI 4 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_parameter_substitution + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/parameter_substitution.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# +ufo_add_test( NAME test_ufo_polygon_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/polygon_check.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) + +# Filters that require CRTM in ObsOperator + +if( crtm_FOUND ) +# + ufo_add_test( NAME test_ufo_airs_qc_filters + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/airs_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsr2_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsr2_qc.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsr2_qc_halo + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsr2_qc_halo.yaml" + MPI 4 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_qc.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_allsky_gfs_gsi_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_allsky_gfs_gsi_qc.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_allsky_gsi_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_allsky_gsi_qc.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_qc_clwretmw + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_qc_clwretmw.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_qc_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_qc_filters_geos + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_qc_filters_geos.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsua_qc_miss_val + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsua_qc_miss_val.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_atms_qc_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atms_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_atms_n20_qc_filters_geos + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atms_n20_qc_filters_geos.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_cris_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/cris_qc.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_cris_qc_filters + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/cris_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_cris_qc_land + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/cris_qc_land.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsr2_qc_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsr2_skylab_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ + TEST_DEPENDS ufo_get_ufo_test_data ufo_get_crtm_test_data ) +# + ufo_add_test( NAME test_ufo_tropics_qc_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/tropics_skylab_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_gmi_skylab_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gmi_skylab_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_gmi_qc_filters + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gmi_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_gmi_qc_filters_geos + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gmi_qc_filters_geos.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_iasi_qc_filters + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/iasi_qc_filters.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_mhs_qc_filters_geos + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/mhs_qc_filters_geos.yaml" + MPI 1 + LIBS ufo + LABELS crtm filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_qc_flags_true + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/abi_g16_qc_flags.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +endif( crtm_FOUND ) + +# Filters that require RTTOV in ObsOperator + +if( ${rttov_FOUND} ) + ufo_add_test( NAME test_ufo_amsr2_rttov_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsr2_rttov_qc.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_amsr2_rttov_ops_qc_rttovonedvarcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/amsr2_rttov_ops_qc_rttovonedvarcheck.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_atms_rttov_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atms_rttov_qc.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_atms_rttov_ops_qc_rttovonedvarcheck + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atms_rttov_ops_qc_rttovonedvarcheck.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_iasi_rttov_ops_qc_rttovonedvarcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/iasi_rttov_ops_qc_rttovonedvarcheck.yaml" + MPI 2 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) + + ufo_add_test( NAME test_ufo_mtgirs_reconrad_obsop_check + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/mtgirs_reconrad_obsop_check.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_ssmis_rttov_ops_qc_rttovonedvarcheck + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/ssmis_rttov_ops_qc_rttovonedvarcheck.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_opr_atovs_rttovonedvar_multiplatform + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atovs_rttovonedvar_multiplatform.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_opr_atovs_rttovonedvar_transmittance + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atovs_rttovonedvar_transmittance.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +# + ufo_add_test( NAME test_ufo_opr_atovs_rttovonedvar_transmittance_multiplatform + TIER 2 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/atovs_rttovonedvar_transmittance_multiplatform.yaml" + MPI 1 + LIBS ufo + LABELS rttov filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +endif( ${rttov_FOUND} ) + + +# Filters that require ROPP in ObsOperator + +if( ${ropp-ufo_FOUND} ) + + ufo_add_test( NAME test_ufo_gnssrobndropp1d_qc + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/test_ObsFilters.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/gnssrobndropp1d_qc.yaml" + MPI 1 + LIBS ufo + LABELS ropp-ufo filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) +endif( ${ropp-ufo_FOUND} ) + +ufo_add_test( NAME test_ufo_preprocess + TIER 1 + ECBUILD + COMMAND ${CMAKE_BINARY_DIR}/bin/ufo_preprocess.x + ARGS "${CMAKE_CURRENT_SOURCE_DIR}/preprocess.yaml" + MPI 1 + LIBS ufo + LABELS filters + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../ ) diff --git a/sorc/_workaround_/PolygonCheck/instantiateObsFilterFactory.h b/sorc/_workaround_/PolygonCheck/instantiateObsFilterFactory.h new file mode 100644 index 000000000..15816398b --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/instantiateObsFilterFactory.h @@ -0,0 +1,225 @@ +/* + * (C) Copyright 2019-2024 UCAR + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + */ + +#ifndef UFO_INSTANTIATEOBSFILTERFACTORY_H_ +#define UFO_INSTANTIATEOBSFILTERFACTORY_H_ + +#include "ufo/filters/AcceptList.h" +#include "ufo/filters/AverageObsToGeoValLevels.h" +#include "ufo/filters/BackgroundCheck.h" +#include "ufo/filters/BayesianBackgroundCheck.h" +#include "ufo/filters/BayesianBackgroundQCFlags.h" +#include "ufo/filters/BlackList.h" +#include "ufo/filters/ConventionalProfileProcessing.h" +#include "ufo/filters/CopyFlagsFromExtendedToOriginalSpace.h" +#include "ufo/filters/CreateDiagnosticFlags.h" +#include "ufo/filters/DifferenceCheck.h" +#include "ufo/filters/EnsembleStatistics.h" +#include "ufo/filters/FinalCheck.h" +#include "ufo/filters/Gaussian_Thinning.h" +#include "ufo/filters/GeoVaLsWriter.h" +#include "ufo/filters/gnssroonedvarcheck/GNSSROOneDVarCheck.h" +#include "ufo/filters/HistoryCheck.h" +#include "ufo/filters/ImpactHeightCheck.h" +#include "ufo/filters/MetOfficeBuddyCheck.h" +#include "ufo/filters/MetOfficeDuplicateCheck.h" +#include "ufo/filters/MetOfficePressureConsistencyCheck.h" +#include "ufo/filters/ModelBestFitPressure.h" +#include "ufo/filters/ModelObThreshold.h" +#include "ufo/filters/MWCLWCheck.h" +#include "ufo/filters/ObsBoundsCheck.h" +#include "ufo/filters/ObsDerivativeCheck.h" +#include "ufo/filters/ObsDiagnosticsWriter.h" +#include "ufo/filters/ObsDomainCheck.h" +#include "ufo/filters/ObsDomainErrCheck.h" +#include "ufo/filters/ObsPolygonCheck.h" +#include "ufo/filters/ObsRefractivityGradientCheck.h" +#include "ufo/filters/ParameterSubstitution.h" +#include "ufo/filters/PerformAction.h" +#include "ufo/filters/PoissonDiskThinning.h" +#include "ufo/filters/PreQC.h" +#include "ufo/filters/PrintFilterData.h" +#include "ufo/filters/ProbabilityGrossErrorWholeReport.h" +#include "ufo/filters/ProcessAMVQI.h" +#include "ufo/filters/ProfileAverageObsToModLevels.h" +#include "ufo/filters/ProfileBackgroundCheck.h" +#include "ufo/filters/ProfileFewObsCheck.h" +#include "ufo/filters/ProfileMaxDifferenceCheck.h" +#include "ufo/filters/ProfileUnFlagObsCheck.h" +#include "ufo/filters/QCmanager.h" +#include "ufo/filters/refractivityonedvarcheck/RefractivityOneDVarCheck.h" +#include "ufo/filters/SatName.h" +#include "ufo/filters/SatwindInversionCorrection.h" +#include "ufo/filters/SpikeAndStepCheck.h" +#include "ufo/filters/StuckCheck.h" +#include "ufo/filters/SuperOb.h" +#include "ufo/filters/SuperRefractionCheckImpactParameter.h" +#include "ufo/filters/SuperRefractionCheckNBAM.h" +#include "ufo/filters/TemporalThinning.h" +#include "ufo/filters/Thinning.h" +#include "ufo/filters/TrackCheck.h" +#include "ufo/filters/TrackCheckShip.h" +#include "ufo/filters/VariableAssignment.h" +#include "ufo/filters/VariableTransforms.h" +#include "ufo/ObsFilterBase.h" +#include "ufo/operators/gnssro/QC/BackgroundCheckRONBAM.h" +#include "ufo/operators/gnssro/QC/ROobserror.h" + +#if defined(GSW_FOUND) + #include "ufo/filters/OceanVerticalStabilityCheck.h" +#endif + +#if defined(RTTOV_FOUND) + #include "ufo/filters/rttovonedvarcheck/RTTOVOneDVarCheck.h" +#endif + +#include "ufo/ObsTraits.h" + +namespace ufo { +void instantiateObsFilterFactory() { + static FilterMaker + acceptListMaker("AcceptList"); + static FilterMaker + backgroundCheckMaker("Background Check"); + static FilterMaker + backgroundCheckRONBAMMaker("Background Check RONBAM"); + static FilterMaker + BayesianBackgroundCheckMaker("Bayesian Background Check"); + static FilterMaker + BayesianBackgroundQCFlagsMaker("Bayesian Background QC Flags"); + static FilterMaker + ProbabilityGrossErrorWholeReportMaker("Bayesian Whole Report"); + static FilterMaker + blackListMaker("BlackList"); // same as RejectList + static FilterMaker + boundsCheckMaker("Bounds Check"); + static FilterMaker + conventionalProfileProcessingMaker("Conventional Profile Processing"); + static FilterMaker + CreateDiagnosticFlagsMaker("Create Diagnostic Flags"); + static FilterMaker + CopyFlagsFromExtendedToOriginalSpaceMaker("Copy Flags From Extended To Original Space"); + static FilterMaker + DerivativeCheckMaker("Derivative Check"); + static FilterMaker + differenceCheckMaker("Difference Check"); + static FilterMaker + domainCheckMaker("Domain Check"); + static FilterMaker + domainErrCheckMaker("DomainErr Check"); + static FilterMaker + polygonCheckMaker("Polygon Check"); + static FilterMaker + finalCheckMaker("Final Check"); + static FilterMaker + gaussianThinningMaker("Gaussian Thinning"); + static FilterMaker + GNSSROOneDVarCheckMaker("GNSS-RO 1DVar Check"); + static FilterMaker + ImpactHeightCheckMaker("GNSSRO Impact Height Check"); + static FilterMaker + historyCheckMaker("History Check"); + static FilterMaker + MetOfficeBuddyCheckMaker("Met Office Buddy Check"); + static FilterMaker + MetOfficeDuplicateCheckMaker("Met Office Duplicate Check"); + static FilterMaker + MetOfficePressureConsistencyCheckMaker("Met Office Pressure Consistency Check"); + static FilterMaker + ModelBestFitPressureMaker("Model Best Fit Pressure"); + static FilterMaker + ModelObThresholdMaker("ModelOb Threshold"); + static FilterMaker + MWCLWCheckMaker("MWCLW Check"); + static FilterMaker + ObsRefractivityGradientCheckMaker("Obs Refractivity Gradient Check"); + static FilterMaker + parameterSubstitutionMaker("Parameter Substitution"); + static FilterMaker + performActionMaker("Perform Action"); + static FilterMaker + poissonDiskThinningMaker("Poisson Disk Thinning"); + static FilterMaker + preQCMaker("PreQC"); + static FilterMaker + printFilterDataMaker("Print Filter Data"); + static FilterMaker + ProcessAMVQIMaker("Process AMV QI"); + static FilterMaker + ProfileAverageObsToModLevelsMaker("Average Observations To Model Levels"); + static FilterMaker + AverageObsToGeoValLevelsMaker("Average Observations To GeoVals Model Levels"); + static FilterMaker + ProfileBackgroundCheckMaker("Profile Background Check"); + static FilterMaker + ProfileFewObsCheckMaker("Profile Few Observations Check"); + static FilterMaker + ProfileMaxDifferenceCheckMaker("Profile Max Difference Check"); + static FilterMaker + ProfileUnFlagObsCheckMaker("Profile Unflag Observations Check"); + static FilterMaker + rejectListMaker("RejectList"); // same as BlackList + static FilterMaker + RefractivityOneDVarCheckMaker("Refractivity 1DVar Check"); + static FilterMaker + ROobserrorMaker("ROobserror"); + static FilterMaker + qcManagerMaker("QCmanager"); + static FilterMaker + satnameCheckMaker("satname"); + static FilterMaker + SatwindInversionCorrectionMaker("Satwind Inversion Correction"); + static FilterMaker + ShipTrackCheckMaker("Ship Track Check"); + static FilterMaker + SpikeAndStepCheckMaker("Spike and Step Check"); + static FilterMaker + StuckCheckMaker("Stuck Check"); + static FilterMaker + SuperRefractionCheckImpactParameterCheckMaker("Impact Parameter Check"); + static FilterMaker + SuperObMaker("SuperOb"); + static FilterMaker + SuperRefractionCheckNBAMCheckMaker("Super Refraction Check NBAM"); + static FilterMaker + temporalThinningMaker("Temporal Thinning"); + static FilterMaker + thinningMaker("Thinning"); + static FilterMaker + TrackCheckMaker("Track Check"); + static FilterMaker + variableAssignmentMaker("Variable Assignment"); + static FilterMaker + VariableTransformsMaker("Variable Transforms"); + static FilterMaker GVWriterMaker("GOMsaver"); + static FilterMaker + YDIAGsaverMaker("YDIAGsaver"); + static FilterMaker + ensembleStatisticsMaker("Ensemble Statistics"); + + // Only include this filter if gsw is present + #if defined(GSW_FOUND) + static FilterMaker + OceanVerticalStabilityCheckMaker("Ocean Vertical Stability Check"); + #endif + + // Only include this filter if rttov is present + #if defined(RTTOV_FOUND) + static FilterMaker + RTTOVOneDVarCheckMaker("RTTOV OneDVar Check"); + #endif + + // For backward compatibility, register some filters under legacy names used in the past + static FilterMaker + legacyGaussianThinningMaker("Gaussian_Thinning"); + static FilterMaker + legacyTemporalThinningMaker("TemporalThinning"); +} + +} // namespace ufo + +#endif // UFO_INSTANTIATEOBSFILTERFACTORY_H_ diff --git a/sorc/_workaround_/PolygonCheck/polygon_check.yaml b/sorc/_workaround_/PolygonCheck/polygon_check.yaml new file mode 100644 index 000000000..efc33b841 --- /dev/null +++ b/sorc/_workaround_/PolygonCheck/polygon_check.yaml @@ -0,0 +1,21 @@ +time window: + begin: 2018-04-14T20:30:00Z + end: 2018-04-15T03:30:00Z + +observations: +- obs space: + name: Radiosonde + obsdatain: + engine: + type: H5File + obsfile: Data/ufo/testinput_tier_1/sondes_obs_2018041500_m.nc4 + simulated variables: [airTemperature, windEastward, windNorthward] + obs filters: + - filter: Polygon Check + inside point longitude: 51 + inside point latitude: 59 + vertex longitudes: [ 50, 50, 200, 200, 125, 50 ] + vertex latitudes: [ 20, 60, 60, 20, 50, 20 ] + action: + name: reduce obs space + passedBenchmark: 30 diff --git a/sorc/build.rdas b/sorc/build.rdas index a9ca3b0ae..be5c200ec 100755 --- a/sorc/build.rdas +++ b/sorc/build.rdas @@ -63,6 +63,26 @@ cp ../_workaround_/RDASApp/saber/GridCheckHelper.cc sorc/saber/src/saber/gsi/uti cp ../_workaround_/RDASApp/saber/GSIParameters.h sorc/saber/src/saber/gsi/utils/GSIParameters.h cp ../_workaround_/RDASApp/saber/Geometry.cc sorc/saber/src/saber/interpolation/Geometry.cc +#----------------------------------------------------------------------- +# These lines should not be merged. They contain the files from this PR: +# +# - https://github.com/JCSDA/ufo/pull/78 +# +# FIXME: Delete this section before merging the PR. + +set -e + +cp ../_workaround_/PolygonCheck/CMakeLists.txt sorc/ufo/src/ufo/filters/CMakeLists.txt +cp ../_workaround_/PolygonCheck/ObsPolygonCheck.cc sorc/ufo/src/ufo/filters/ObsPolygonCheck.cc +cp ../_workaround_/PolygonCheck/ObsPolygonCheck.h sorc/ufo/src/ufo/filters/ObsPolygonCheck.h +cp ../_workaround_/PolygonCheck/instantiateObsFilterFactory.h sorc/ufo/src/ufo/instantiateObsFilterFactory.h +cp ../_workaround_/PolygonCheck/filtersCMakeLists.txt sorc/ufo/test/testinput/unit_tests/filters/CMakeLists.txt +cp ../_workaround_/PolygonCheck/polygon_check.yaml sorc/ufo/test/testinput/unit_tests/filters/polygon_check.yaml + +set +e + +#----------------------------------------------------------------------- + rm -rf build/ ./build.sh -m MPAS -t NO -w NO -b NO diff --git a/ush/yamlify_domain_edge.py b/ush/yamlify_domain_edge.py new file mode 100755 index 000000000..bc826d535 --- /dev/null +++ b/ush/yamlify_domain_edge.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +import netCDF4 as nc +import numpy as np +import argparse +import warnings +from collections import defaultdict + +""" +This program outputs the computational domain edge in a YAML format expected by the UFO Polygon Filter. +""" + +# Disable warnings +warnings.filterwarnings('ignore') + + +def normalize_lon(lon): + lon = np.asarray(lon) + return np.where(lon < 0.0, lon + 360.0, lon) + + +def to_plain_array(a): + # netCDF masked arrays to plain ndarray + return np.array(a.filled(np.nan)) if np.ma.isMaskedArray(a) else np.array(a) + + +def polygon_from_structured_edges(grid_ds): + """ + Build a domain boundary ring from a structured FV3-style grid using only + the outer perimeter (no triangulation). Works for variables named either + (grid_lat, grid_lon) or (grid_latt, grid_lont). + """ + vars_ = grid_ds.variables + # Accept common FV3 names + if 'grid_lat' in vars_ and 'grid_lon' in vars_: + glat = np.array(vars_['grid_lat'][:]) + glon = np.array(vars_['grid_lon'][:]) + elif 'grid_latt' in vars_ and 'grid_lont' in vars_: + glat = np.array(vars_['grid_latt'][:]) + glon = np.array(vars_['grid_lont'][:]) + else: + raise RuntimeError( + "Structured grid expected but did not find grid_lat/grid_lon or grid_latt/grid_lont." + ) + + if glat.ndim != 2 or glon.ndim != 2 or glat.shape != glon.shape: + raise RuntimeError("grid_lat/grid_lon must be 2-D arrays of the same shape.") + + # Normalize longitudes to [0,360) + glon = normalize_lon(glon) + + # Extract perimeter in CCW order: top > right > bottom > left + top = np.c_[glon[0, :], glat[0, :]] + right = np.c_[glon[1:, -1], glat[1:, -1]] + bottom = np.c_[glon[-1, -2::-1], glat[-1, -2::-1]] # exclude last to avoid dup + left = np.c_[glon[-2:0:-1, 0], glat[-2:0:-1, 0]] # exclude corners already used + + ring = np.vstack([top, right, bottom, left]) + return ring + + +def polygon_from_mpas_boundary(grid_ds, simplify_target=20000): + """ + Build the exact MPAS outer boundary by walking boundary edges. + Returns ring as (N,2) [lon_deg, lat_deg] in [0,360) lon (no seam shift yet). + simplify_target: if the ring has more vertices than this, subsample it. + """ + cellsOnEdge = to_plain_array(grid_ds.variables["cellsOnEdge"][:]) # (nEdges, 2), int + verticesOnEdge = to_plain_array(grid_ds.variables["verticesOnEdge"][:]) # (nEdges, 2), int + lonVertex = to_plain_array(grid_ds.variables["lonVertex"][:]) # (nVertices,) + latVertex = to_plain_array(grid_ds.variables["latVertex"][:]) + + # Convert to degrees; clean invalids + lonv = np.degrees(lonVertex) + latv = np.degrees(latVertex) + goodv = np.isfinite(lonv) & np.isfinite(latv) + if not goodv.all(): + # If any bad vertices exist, just ignore edges touching them + pass + + # Boundary edges have a missing neighbor (cell id == 0) + ce = cellsOnEdge.astype(np.int64) + boundary_mask = (ce[:, 0] == 0) | (ce[:, 1] == 0) + if not np.any(boundary_mask): + raise RuntimeError("No boundary edges found (is this a global mesh?).") + + # Convert to 0-based; drop invalids (<=0) and edges that touch bad vertices + bedges = verticesOnEdge[boundary_mask].astype(np.int64) # 1-based indices + v1 = bedges[:, 0] - 1 + v2 = bedges[:, 1] - 1 + ok = (v1 >= 0) & (v2 >= 0) + if not goodv.all(): + ok &= goodv[v1] & goodv[v2] + v1, v2 = v1[ok], v2[ok] + + # Build adjacency along boundary + adj = defaultdict(list) + for a, b in zip(v1, v2): + adj[a].append(b) + adj[b].append(a) + + # Each boundary vertex should have degree 2 (closed polygon). + # If not, we still try to walk and skip dead-ends. + visited_e = set() + loops = [] + for s in list(adj.keys()): + for nb in adj[s]: + e = (min(s, nb), max(s, nb)) + if e in visited_e: + continue + # Trace a loop starting with edge + ring_idx = [s, nb] + visited_e.add(e) + prev, cur = s, nb + while True: + nbs = adj[cur] + # Pick the neighbor that isn't the one we came from + nxt = nbs[0] if nbs[0] != prev else (nbs[1] if len(nbs) > 1 else None) + if nxt is None: + break + e2 = (min(cur, nxt), max(cur, nxt)) + if e2 in visited_e: + # closed? + if nxt == ring_idx[0]: + loops.append(ring_idx) + break + visited_e.add(e2) + ring_idx.append(nxt) + prev, cur = cur, nxt + if cur == ring_idx[0]: + loops.append(ring_idx) + break + + if not loops: + raise RuntimeError("Could not assemble a boundary loop from MPAS edges.") + + # Choose the largest loop (by vertex count) + ring_ids = max(loops, key=len) + + # Compose lon/lat; normalize lon to [0,360) + lon = lonv[ring_ids] + lat = latv[ring_ids] + lon = np.where(lon < 0.0, lon + 360.0, lon) + ring = np.c_[lon, lat] + + # Simplification wherein if the ring has more vertices than this, subsample it. + if simplify_target and ring.shape[0] > simplify_target: + stride = max(1, ring.shape[0] // simplify_target) + ring = ring[::stride] + + return ring + + +def build_domain_ring(grid_ds): + varsin = grid_ds.variables.keys() + if (('grid_lat' in varsin and 'grid_lon' in varsin) or ('grid_latt' in varsin and 'grid_lont' in varsin)): + ring = polygon_from_structured_edges(grid_ds) + elif {'cellsOnEdge', 'verticesOnEdge', 'lonVertex', 'latVertex'}.issubset(varsin): + ring = polygon_from_mpas_boundary(grid_ds, simplify_target=20000) + else: + raise RuntimeError("Unsupported grid file: need grid_lat/grid_lon (or grid_latt/grid_lont) or cells/verticesOnEdge") + + # Normalize and optionally fix the dateline seam + ring[:, 0] = normalize_lon(ring[:, 0]) + L = ring[:, 0] + span_direct = L.max() - L.min() + L_shift = np.where(L > 180.0, L - 360.0, L) + span_shift = L_shift.max() - L_shift.min() + lon_offset = -360 if span_shift < span_direct else 0 + if lon_offset == -360: + ring[:, 0] = L_shift + return ring + + +def print_ring(ring, lonlat, indent, columns=8): + nring = len(ring) + for i in range(nring): + if i % columns == 0 and i < nring - 1: + if i: + print(',') + print(indent, end='') + elif i: + print(', ', end='') + # A 3km-resolution MPAS domain had points that differed by + # .001 degrees, hence the resolution of .0001 + print('%8.4f' % ring[i][lonlat], end='') + + +# Parse command-line arguments +# Note: +# The grid file is what contains variables grid_lat/grid_lon +# OR latCell/lonCell for FV3 and MPAS respectively. +# Examples can be found in the following rrfs-test cases: +# - rrfs-data_fv3jedi_2022052619/Data/bkg/fv3_grid_spec.nc +# - mpas_2024052700/data/restart.2024-05-27_00.00.00.nc +parser = argparse.ArgumentParser() +parser.add_argument('-g', '--grid', type=str, help='grid file', required=True) +parser.add_argument('-i', '--indent', type=str, help='indent', required=False, default='') +args = parser.parse_args() + +# Assign filenames +grid_filename = args.grid # see note above. + +grid_ds = nc.Dataset(grid_filename, 'r') + +# Build ring +ring = build_domain_ring(grid_ds) +centroid = np.nanmean(ring, axis=0) + +indent = args.indent + +print(f'''{indent}polygon: &POLY +{indent} filter: Polygon Check +{indent} action: +{indent} name: reduce obs space +{indent} inside point longitude: {centroid[0]:.4f} +{indent} inside point latitude: {centroid[1]:.4f}''') + +print(f'{indent} vertex longitudes: [') +print_ring(ring, 0, f'{indent} ') +print(f'\n{indent} ]') + +print(f'{indent} vertex latitudes: [') +print_ring(ring, 1, f'{indent} ') +print(f'\n{indent} ]')