!******************************************************************************** !> @file !> NAME: AMV_EN_Wind_Data_m !> !> FUNCTION: Wind_Data is anything tracked per target. !> !> DESCRIPTION: !> At the end of processing all of the data in wind data gets separated into separate variables via PutTargetData. !> TargetData_t also exists to store per-target data but exists to support named variables instead of winds_data(variable,target_num) convention. !> Note that the per-target data has an entire capability section dedicated to it (capability/perTarget/) !> !> HISTORY: !> - 06/2019 - Brian Helgans - Created. !> !> @ingroup WINDS_AMV_EN !******************************************************************************** MODULE AMV_EN_Wind_Data_M !API Related Modules USE cf_data_mod USE ds_data_mod USE fw_log_mod USE fw_misc_mod USE fw_scene_mod USE URIHelper_mod USE GEOCAT_CONSTANTS USE AMV_EN_WINDS_INC USE AMV_EN_XPATH_M USE AMV_EN_Output_M USE AMV_EN_DBSCAN_M IMPLICIT NONE PRIVATE PUBLIC :: PutTargetData !< puts target data into data cache PUBLIC :: Update_Wind_Data !< updates the winds_data context PUBLIC :: TargetData_t !< advised alternative to Winds_Data and it's constructor. It automatically destructs. INTEGER(LONG),PARAMETER, PUBLIC :: FIRST=1 !< first image array index INTEGER(LONG),PARAMETER, PUBLIC :: MIDDLE=2 !< Middle image array index INTEGER(LONG),PARAMETER, PUBLIC :: LAST=3 !< last image array index INTEGER(LONG),PARAMETER, PUBLIC :: NUMBER_TIMESTEPS = 3 !< first, middle, and last TYPE TargetData_t INTEGER(LONG), DIMENSION(:,:), ALLOCATABLE :: EpochTimes !< (first,middle,last) times per target !LOGICAL, DIMENSION(:), ALLOCATABLE :: inROI !< bool indicating if the point is within ROI. !inROI is recommended for moving post processing routines into segment processing and to support coherance check that needs access to targets outside of the ROI INTEGER(LONG) :: TargetNumber CONTAINS PROCEDURE :: Create FINAL :: Destroy END TYPE TargetData_t CONTAINS !> @brief Constructor !> @return TRUE if successful FUNCTION Create(targetData, BufferLength) RESULT(res) CHARACTER(len=*), PARAMETER :: FUNC = "Create_TargetData" CLASS(TargetData_t) :: targetData !< the type being constructed. INTEGER(LONG), INTENT(IN) :: BufferLength !< overestimate of how many possible winds targets will be found. LOGICAL :: res INTEGER :: status ALLOCATE(targetData%EpochTimes(BufferLength, NUMBER_TIMESTEPS), stat = status) IF(status == 0) THEN res = .TRUE. ELSE res = .FALSE. CALL fw_log_error(FUNC,"Failed to allocate Target Data") ENDIF END FUNCTION Create !> @brief Destructor. !> Might as well rely upon automatic deallocation once f2008 standard flag is enforced by compiler. !> @return TRUE if successful SUBROUTINE Destroy(this) TYPE(TargetData_t) :: this IF(ALLOCATED(this%EpochTimes)) DEALLOCATE(this%EpochTimes) END SUBROUTINE Destroy !> @brief Update the array holding the AMV data. !> !> Updates the Wind_Data array with information from current target and !> increments the element counter for the next target scene. !> !> @authors !> - 04/2010 - Wayne Bresky - Created !> - 08/2010 - Wayne Bresky - Added DBSCAN data structure !> - 10/2023 - Andy Bailey - Added Box_Data data structure SUBROUTINE Update_Wind_Data(Wind_Data, TargetData, Error_Counts, Target_Number, Good_Winds, EpochTimes, QC_Flag, Output, DBSCAN_Out, CSWV_Flag, MAX_WIND_RECORDS, Box_Data) USE AMV_EN_Time_M, ONLY: Epoch_to_HHMMSS USE AMV_EN_WINDS_INC USE AMV_EN_TargetBox_m ! aab - added for Box_Data/CloudyPixels IMPLICIT NONE CHARACTER(LEN=*), PARAMETER :: FUNC = "Update_Wind_Data" REAL(SINGLE), DIMENSION(:, :), INTENT(INOUT) :: Wind_Data !< stores many variables per-target. Wind_data(variableIndex, targetNumber) TYPE(TargetData_t), INTENT(INOUT) :: TargetData !< stores many variables per-target. INTEGER(LONG), DIMENSION(41), INTENT(INOUT) :: Error_Counts(-10:30) !< running count of errors INTEGER(LONG), INTENT(INOUT) :: Target_Number !< current number of targets and will be updated if the found target is unique. INTEGER(LONG), INTENT(INOUT) :: Good_Winds !< number of good winds INTEGER(LONG), DIMENSION(3), INTENT(IN) :: EpochTimes !< time of each target (approximate, can be nominal image time) INTEGER(LONG), INTENT(IN) :: QC_Flag !< QC of the current target. TYPE(Output_Variables), INTENT(IN) :: Output !< output for the tracking which will be copied into the "per-target" array TYPE(DBSCAN_Output), INTENT(IN) :: DBSCAN_Out !< results of Density based spatial clustering INTEGER(LONG), INTENT(IN) :: CSWV_Flag !< sym%yes if clear sky tracking. Really interested in if nested tracking occurred. INTEGER(LONG), INTENT(IN) :: MAX_WIND_RECORDS !< size of wind_data target array. TYPE(Target_Box_Data), INTENT(IN) :: Box_Data !< aab - added for CloudyPixels LOGICAL :: Unique !< the target may match the previous target, this is not desired. ! make sure target has valid lat/lon before proceeding IF (Output%Lat_Target .NE. MISSING_VALUE_REAL4 .AND. Output%Lon_Target .NE. MISSING_VALUE_REAL4) THEN ! Increment counter and add data to Wind_Data array Unique = .FALSE. IF ( Target_Number .EQ. 0 ) THEN ! this is the first record Unique = .TRUE. ELSE ! is this target unique? comparing only with previous one IF ( Output%Lat_Target .EQ. Wind_Data(Target_Number, 1) .AND. & Output%Lon_Target .EQ. Wind_Data(Target_Number, 2) .AND. & QC_Flag .EQ. Wind_Data(Target_Number, 28)) THEN Unique = .FALSE. ELSE Unique = .TRUE. ENDIF ENDIF IF ( Unique ) THEN IF ( QC_Flag .EQ. 0 ) Good_Winds = Good_Winds + 1 Error_Counts(QC_Flag) = Error_Counts(QC_Flag) + 1_BYTE Target_Number = Target_Number + 1 IF ( Target_Number .GT. MAX_WIND_RECORDS ) THEN CALL fw_log_warning(FUNC, 'Target_Number is greater MAX_WIND_RECORDS') RETURN ENDIF Wind_Data(Target_Number, 1) = Output%Lat_Target Wind_Data(Target_Number, 2) = Output%Lon_Target Wind_Data(Target_Number, 3) = Output%U_Avg Wind_Data(Target_Number, 4) = Output%V_Avg Wind_Data(Target_Number, 5) = Output%U_Component Wind_Data(Target_Number, 6) = Output%V_Component Wind_Data(Target_Number, 7) = Output%U_Component2 Wind_Data(Target_Number, 8) = Output%V_Component2 Wind_Data(Target_Number, 9) = Output%Median_Press Wind_Data(Target_Number, 14) = Output%Median_BrtTemp ! -------------------------------------------------------------------------- ! If using nested tracking and not the clear-sky WV , replace the cold ! sample median pressure with the median pressure of the combined sample. ! For the clear-sky WV use brightness temperature. ! ! Do not use combined median if low-level inversion is present ! -------------------------------------------------------------------------- IF (CSWV_Flag .EQ. sym%NO) THEN IF (Output%Flag_5x5 .EQ. sym%YES) THEN ! Replace cold sample CTP with median CTP of largest motion cluster IF (Output%Combined_Median .NE. MISSING_VALUE_REAL4) THEN Wind_Data(Target_Number, 9) = Output%Combined_Median Wind_Data(Target_Number, 14) = Output%Combined_Median_CldTemp ENDIF ENDIF ENDIF Wind_Data(Target_Number, 10) = Output%U_Fcst Wind_Data(Target_Number, 11) = Output%V_Fcst ! if target fails, set wind values to missing IF (QC_Flag .GT. 0) THEN Wind_Data(Target_Number, 5) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 6) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 7) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 8) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 10) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 11) = MISSING_VALUE_REAL4 ENDIF Wind_Data(Target_Number, 12) = Output%Corr_Coeff Wind_Data(Target_Number, 13) = Output%Corr_Coeff2 Wind_Data(Target_Number, 15) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 16) = Output%X_NWP_Target Wind_Data(Target_Number, 17) = Output%Y_NWP_Target ! array elements 15 and 18-24 are filled by QI program ! (15) Output QI score (weighted average of all tests) ! (18) QI test 1 - speed consistency ! (19) QI test 2 - direction consistency ! (20) QI test 3 - vector consistency ! (21) QI test 6 - buddy consistency (closest neighbor) ! (22) QI test 7 - forecast consistency ! (23) Vector difference with forecast ! (24) Forecast speed IF (Output%Variance_Press .GE. 0.0) Wind_Data(Target_Number, 26) = & SQRT(Output%Variance_Press) Wind_Data(Target_Number, 27) = Output%Sat_Zenith_Angle Wind_Data(Target_Number, 28) = QC_Flag Wind_Data(Target_Number, 29) = Output%Lat_Match Wind_Data(Target_Number, 30) = Output%Lon_Match Wind_Data(Target_Number, 31) = Output%Lat_Match2 Wind_Data(Target_Number, 32) = Output%Lon_Match2 Wind_Data(Target_Number, 33) = Output%Channel Wind_Data(Target_Number, 34) = Output%Point_Index Wind_Data(Target_Number, 35) = Output%Flag_5x5 Wind_Data(Target_Number, 36) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 37) = MISSING_VALUE_REAL4 Wind_Data(Target_Number, 39) = DBSCAN_Out%StdDev_MVD1 Wind_Data(Target_Number, 40) = DBSCAN_Out%StdDev_MVD2 Wind_Data(Target_Number, 41) = DBSCAN_Out%PctOfAvg1 Wind_Data(Target_Number, 42) = DBSCAN_Out%PctOfAvg2 Wind_Data(Target_Number, 43) = DBSCAN_Out%NumberOfClusters1 Wind_Data(Target_Number, 44) = DBSCAN_Out%MaxClusterSize1 Wind_Data(Target_Number, 45) = DBSCAN_Out%NumberOfClusters2 Wind_Data(Target_Number, 46) = DBSCAN_Out%MaxClusterSize2 Wind_Data(Target_Number, 47) = Output%Combined_Median_Hgt Wind_Data(Target_Number, 49) = DBSCAN_Out%Number_CTP_Sample1 Wind_Data(Target_Number, 50) = DBSCAN_Out%Number_CTP_Sample2 Wind_Data(Target_Number, 51) = Output%Land_Flag Wind_Data(Target_Number, 52) = Output%Inversion_Flag Wind_Data(Target_Number, 53) = Output%Cloud_Phase Wind_Data(Target_Number, 54) = Output%Cloud_Type Wind_Data(Target_Number, 55) = CSWV_Flag ! array elements 57 and 58 (temp gradient and wind shear) are filled ! in the expected_error subroutine Wind_Data(Target_Number, 59) = Output%Min_CTP Wind_Data(Target_Number, 60) = Output%Max_CTP Wind_Data(Target_Number, 61) = Output%Min_CTT Wind_Data(Target_Number, 62) = Output%Max_CTT Wind_Data(Target_Number, 63) = Output%Combined_Median_HgtErr Wind_Data(Target_Number, 64) = Output%Combined_Median_TempErr Wind_Data(Target_Number, 65) = Output%Spd_Fcst_Original_Press Wind_Data(Target_Number, 66) = Output%Dir_Fcst_Original_Press Wind_Data(Target_Number, 68) = Output%Weighted_PW Wind_Data(Target_Number, 69) = DBSCAN_Out%Max1_PctOfSample Wind_Data(Target_Number, 70) = DBSCAN_Out%Max2_PctOfSample Wind_Data(Target_Number, 71) = Output%Min_OD Wind_Data(Target_Number, 72) = Output%Max_OD Wind_Data(Target_Number, 73) = Output%Median_OD Wind_Data(Target_Number, 74) = Output%Min_Cost Wind_Data(Target_Number, 75) = Output%Max_Cost Wind_Data(Target_Number, 76) = Output%Median_Cost ! add image coordinates of target center - wcb 12/2/15 Wind_Data(Target_Number, 77) = Output%Target_Element Wind_Data(Target_Number, 78) = Output%Target_Line Wind_Data(Target_Number, 79) = Epoch_to_HHMMSS(EpochTimes(MIDDLE)) !not used anywhere but filled Wind_Data(Target_Number, 80) = Epoch_to_HHMMSS(EpochTimes(FIRST)) !not used anywhere but filled Wind_Data(Target_Number, 81) = Epoch_to_HHMMSS(EpochTimes(LAST)) !not used anywhere but filled Wind_Data(Target_Number, 82) = Box_Data%CloudyPixels !< aab - add CloudyPixels TargetData%EpochTimes(Target_Number,:) = EpochTimes ENDIF ENDIF END SUBROUTINE Update_Wind_Data !> breaks apart all the winds results into each variable array FUNCTION PutTargetData(Wind_Data, Target_Number, lonSign) RESULT(ret) USE AMV_EN_WINDS_INC USE COMMON_VAR_VALUE USE GranuleLevelQF_Mod IMPLICIT NONE CHARACTER(LEN=*), PARAMETER :: FUNC = "PutTargetData" REAL(SINGLE), DIMENSION(:, :), TARGET, INTENT(IN) :: Wind_Data !< stores many variables per-target. Wind_data(variableIndex, targetNumber) REAL(SINGLE), INTENT(IN) :: lonSign !< +1.0 or -1.0. it seems longitude has the wrong sign for polar satellites. INTEGER(LONG), INTENT(IN) :: Target_Number !< number of targets processed LOGICAL :: ret REAL(SINGLE), DIMENSION(:), POINTER :: WindLat REAL(SINGLE), DIMENSION(:), POINTER :: WindLon REAL(SINGLE), DIMENSION(:), POINTER :: WindSpd REAL(SINGLE), DIMENSION(:), POINTER :: WindDir REAL(SINGLE), DIMENSION(:), POINTER :: UComponent REAL(SINGLE), DIMENSION(:), POINTER :: VComponent REAL(SINGLE), DIMENSION(:), POINTER :: UComponent2 REAL(SINGLE), DIMENSION(:), POINTER :: VComponent2 REAL(SINGLE), DIMENSION(:), POINTER :: MedianPress REAL(SINGLE), DIMENSION(:), POINTER :: UFcst REAL(SINGLE), DIMENSION(:), POINTER :: VFcst REAL(SINGLE), DIMENSION(:), POINTER :: CorrCoeff REAL(SINGLE), DIMENSION(:), POINTER :: CorrCoeff2 REAL(SINGLE), DIMENSION(:), POINTER :: MedianBT INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: QI INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: SpdFlag INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: DirFlag INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: VecFlag INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: LocConsistencyFlg INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: FcstFlg ! Add QINF (QI without forecast) variable INTEGER(LONG), DIMENSION(:), ALLOCATABLE :: QINF REAL(SINGLE), DIMENSION(:), POINTER :: ExpectedErr REAL(SINGLE), DIMENSION(:), POINTER :: VariancePress REAL(SINGLE), DIMENSION(:), POINTER :: SatZen INTEGER(LONG), DIMENSION(:), POINTER :: Flag REAL(SINGLE), DIMENSION(:), POINTER :: LatMatch REAL(SINGLE), DIMENSION(:), POINTER :: LonMatch REAL(SINGLE), DIMENSION(:), POINTER :: LatMatch2 REAL(SINGLE), DIMENSION(:), POINTER :: LonMatch2 INTEGER(LONG), DIMENSION(:), POINTER :: PointIndex REAL(SINGLE), DIMENSION(:), POINTER :: StdDevMVD1 REAL(SINGLE), DIMENSION(:), POINTER :: StdDevMVD2 REAL(SINGLE), DIMENSION(:), POINTER :: PctOfAvg1 REAL(SINGLE), DIMENSION(:), POINTER :: PctOfAvg2 INTEGER(LONG), DIMENSION(:), POINTER :: NumClusters1 INTEGER(LONG), DIMENSION(:), POINTER :: MaxClusterSize1 INTEGER(LONG), DIMENSION(:), POINTER :: NumClusters2 INTEGER(LONG), DIMENSION(:), POINTER :: MaxClusterSize2 INTEGER(LONG), DIMENSION(:), POINTER :: LandFlag INTEGER(LONG), DIMENSION(:), POINTER :: InversionFlag INTEGER(LONG), DIMENSION(:), POINTER :: CloudPhase INTEGER(LONG), DIMENSION(:), POINTER :: CloudType REAL(SINGLE), DIMENSION(:), POINTER :: TempGrad REAL(SINGLE), DIMENSION(:), POINTER :: ShearPtr REAL(SINGLE), DIMENSION(:), POINTER :: MinCTP REAL(SINGLE), DIMENSION(:), POINTER :: MaxCTP REAL(SINGLE), DIMENSION(:), POINTER :: MinCTT REAL(SINGLE), DIMENSION(:), POINTER :: MaxCTT REAL(SINGLE), DIMENSION(:), POINTER :: MedianHgtErr REAL(SINGLE), DIMENSION(:), POINTER :: MedianTempErr REAL(SINGLE), DIMENSION(:), POINTER :: Altitude REAL(SINGLE), DIMENSION(:), POINTER :: OrigFcstSpd REAL(SINGLE), DIMENSION(:), POINTER :: OrigFcstDir REAL(SINGLE), DIMENSION(:), POINTER :: BestFitPresLvl REAL(SINGLE), DIMENSION(:), POINTER :: WghtCTP REAL(SINGLE), DIMENSION(:), POINTER :: MaxPct1 REAL(SINGLE), DIMENSION(:), POINTER :: MaxPct2 REAL(SINGLE), DIMENSION(:), POINTER :: Min_OD REAL(SINGLE), DIMENSION(:), POINTER :: Max_OD REAL(SINGLE), DIMENSION(:), POINTER :: Median_OD REAL(SINGLE), DIMENSION(:), POINTER :: Min_ACHA_COST REAL(SINGLE), DIMENSION(:), POINTER :: Max_ACHA_COST REAL(SINGLE), DIMENSION(:), POINTER :: Median_ACHA_COST REAL(SINGLE), DIMENSION(:), POINTER :: Element !< target center element REAL(SINGLE), DIMENSION(:), POINTER :: Line !< target center line INTEGER(LONG), DIMENSION(:), POINTER :: CloudyPixels !< aab - add CloudyPixels REAL(SINGLE), PARAMETER :: CAT_PRESS_100 = 100.0 REAL(SINGLE), PARAMETER :: CAT_PRESS_400 = 400.0 REAL(SINGLE), PARAMETER :: CAT_PRESS_700 = 700.0 REAL(SINGLE), PARAMETER :: CAT_PRESS_1000 = 1000.0 ! degradation related variables. CHARACTER(len=:), ALLOCATABLE :: targetType LOGICAL :: acha_mitigation_flag INTEGER(LONG) :: good_flag_value TYPE(GranuleLevelQF_t) :: DegradationQF_Cloud_Height LOGICAL :: isSecondChoice !< indicates the channel is less than optimal (e.g. G17 mitigation) LOGICAL :: ihas REAL(SINGLE) :: aValue INTEGER(LONG) :: I ret = .FALSE. isSecondChoice = .FALSE. IF(target_number < 1) THEN ret = .TRUE. RETURN ENDIF !< determine if G17 mitigation is in effect. IF(.NOT. cf_has(PAR_SECOND_CHOICE_LBL, ihas, FUNC)) RETURN IF(ihas) THEN IF(.NOT. cf_get(PAR_SECOND_CHOICE_LBL, isSecondChoice, FUNC)) RETURN ENDIF ! get the cloud height degradation flag of the first segment and determine if it was degraded. IF(.NOT.ds_get(INPUT_CLD_HEIGHT_DEGRAD_LBL, DegradationQF_Cloud_Height%flag, FUNC, seg=1)) RETURN IF(DegradationQF_Cloud_Height%isChannelMissing()) THEN acha_mitigation_flag = .TRUE. ELSE acha_mitigation_flag = .FALSE. ENDIF ! 1. backup channel. ! 2. ACHA degrade (while tracking clouds) ! 3. backup channel and ACHA degrade. Consider checking if tracking clouds? ! 0. No degrade IF(.NOT. cf_get(PAR_TARGET_TYPE_LBL, targetType, FUNC)) RETURN IF( isSecondChoice .AND. (.NOT. acha_mitigation_flag) ) THEN good_flag_value = -1 ELSEIF( (.NOT. isSecondChoice) .AND. acha_mitigation_flag .AND. targetType == TARGET_CLOUD) THEN good_flag_value = -2 ELSEIF( isSecondChoice .AND. acha_mitigation_flag ) THEN good_flag_value = -3 ELSE good_flag_value = 0 ENDIF WindLat => Wind_Data(1:Target_Number, 1) IF(.NOT.ds_put(WIND_LAT_LBL, WindLat, FUNC)) RETURN IF(.NOT.ds_shape_alloc(WIND_LON_LBL,Target_Number, WindLon, FUNC)) RETURN DO I = 1, Target_Number aValue = Wind_Data(I, 2) IF ( aValue .NE. MISSING_VALUE_REAL4) THEN WindLon(I) = aValue*lonSign ELSE WindLon(I) = MISSING_VALUE_REAL4 ENDIF ENDDO WindSpd => Wind_Data(1:Target_Number, 3) IF(.NOT.ds_put(WIND_SPEED_LBL, WindSpd, FUNC)) RETURN WindDir => Wind_Data(1:Target_Number, 4) IF(.NOT.ds_put(WIND_DIRECTION_LBL, WindDir, FUNC)) RETURN UComponent => Wind_Data(1:Target_Number, 5) IF(.NOT.ds_put(U_COMPONENT_1_LBL, UComponent, FUNC)) RETURN VComponent => Wind_Data(1:Target_Number, 6) IF(.NOT.ds_put(V_COMPONENT_1_LBL, VComponent, FUNC)) RETURN UComponent2 => Wind_Data(1:Target_Number, 7) IF(.NOT.ds_put(U_COMPONENT_2_LBL, UComponent2, FUNC)) RETURN VComponent2 => Wind_Data(1:Target_Number, 8) IF(.NOT.ds_put(V_COMPONENT2_LBL, VComponent2, FUNC)) RETURN MedianPress => Wind_Data(1:Target_Number, 9) IF(.NOT.ds_put(MEDIAN_PRESS_LBL, MedianPress, FUNC)) RETURN UFcst => Wind_Data(1:Target_Number, 10) IF(.NOT.ds_put(FCST_SPD_LBL, UFcst, FUNC)) RETURN VFcst => Wind_Data(1:Target_Number, 11) IF(.NOT.ds_put(FCST_DIR_LBL, VFcst, FUNC)) RETURN CorrCoeff => Wind_Data(1:Target_Number, 12) IF(.NOT.ds_put(CORR_COEFF_LBL, CorrCoeff, FUNC)) RETURN CorrCoeff2 => Wind_Data(1:Target_Number, 13) IF(.NOT.ds_put(CORR_COEFF2_LBL, CorrCoeff2, FUNC)) RETURN MedianBT => Wind_Data(1:Target_Number, 14) IF(.NOT.ds_put(MEDIAN_BT_LBL, MedianBT, FUNC)) RETURN ALLOCATE(QI(Target_Number)) QI = NINT(HUNDRED * Wind_Data(1:Target_Number, 15)) IF(.NOT.ds_put(QI_LBL, QI, FUNC)) RETURN DEALLOCATE(QI) ALLOCATE(SpdFlag(Target_Number)) SpdFlag = NINT(HUNDRED * Wind_Data(1:Target_Number, 18)) IF(.NOT.ds_put(SPD_FLAG_LBL, SpdFlag, FUNC)) RETURN DEALLOCATE(SpdFlag) ALLOCATE(DirFlag(Target_Number)) DirFlag = NINT(HUNDRED * Wind_Data(1:Target_Number, 19)) IF(.NOT.ds_put(DIR_FLAG_LBL, DirFlag, FUNC)) RETURN DEALLOCATE(DirFlag) ALLOCATE(VecFlag(Target_Number)) VecFlag = NINT(HUNDRED * Wind_Data(1:Target_Number, 20)) IF(.NOT.ds_put(VEC_FLAG_LBL, VecFlag, FUNC)) RETURN DEALLOCATE(VecFlag) ALLOCATE(LocConsistencyFlg(Target_Number)) LocConsistencyFlg = NINT(HUNDRED * Wind_Data(1:Target_Number, 21)) IF(.NOT.ds_put(LOC_CONSISTENCY_FLG_LBL, LocConsistencyFlg, FUNC)) RETURN DEALLOCATE(LocConsistencyFlg) ALLOCATE(FcstFlg(Target_Number)) FcstFlg = NINT(HUNDRED * Wind_Data(1:Target_Number, 22)) IF(.NOT.ds_put(FCST_FLAG_LBL, FcstFlg, FUNC)) RETURN DEALLOCATE(FcstFlg) ! Add QINF (QI without forecast) variable ALLOCATE(QINF(Target_Number)) QINF = NINT(HUNDRED * Wind_Data(1:Target_Number, 89)) IF(.NOT.ds_put(QINF_LBL, QINF, FUNC)) RETURN DEALLOCATE(QINF) ExpectedErr => Wind_Data(1:Target_Number, 25) IF(.NOT.ds_put(EXPECTED_ERR_LBL, ExpectedErr, FUNC)) RETURN VariancePress => Wind_Data(1:Target_Number, 26) IF(.NOT.ds_put(PRESSURE_VARIANCE_LBL, VariancePress, FUNC)) RETURN SatZen => Wind_Data(1:Target_Number, 27) IF(.NOT.ds_put(SAT_ZEN_LBL, SatZen, FUNC)) RETURN IF(.NOT.ds_shape_alloc(FLAG_LBL, Target_Number, Flag, FUNC)) RETURN Flag = NINT(Wind_Data(1:Target_Number, 28)) IF(good_flag_value /= 0) THEN DO I = 1,Target_Number IF(Flag(I) == 0 ) Flag(I) = good_flag_value ENDDO ENDIF LatMatch => Wind_Data(1:Target_Number, 29) IF(.NOT.ds_put(LAT_MATCH1_LBL, LatMatch, FUNC)) RETURN IF(.NOT.ds_shape_alloc(LON_MATCH1_LBL, Target_Number, LonMatch, FUNC)) RETURN DO I = 1,Target_Number aValue = Wind_Data(I, 30) IF ( aValue .NE. MISSING_VALUE_REAL4) THEN LonMatch(I) = aValue*lonSign ELSE LonMatch(I) = MISSING_VALUE_REAL4 ENDIF ENDDO LatMatch2 => Wind_Data(1:Target_Number, 31) IF(.NOT.ds_put(LAT_MATCH2_LBL, LatMatch2, FUNC)) RETURN IF(.NOT.ds_shape_alloc(LON_MATCH2_LBL,Target_Number, LonMatch2, FUNC)) RETURN DO I = 1, Target_Number aValue = Wind_Data(I, 32) IF ( aValue .NE. MISSING_VALUE_REAL4) THEN LonMatch2(I) = aValue*lonSign ELSE LonMatch2(I) = MISSING_VALUE_REAL4 ENDIF ENDDO IF(.NOT.ds_shape_alloc(POINT_INDEX_LBL,Target_Number, PointIndex, FUNC)) RETURN DO I = 1, Target_Number PointIndex(I) = INT(Wind_Data(I, 34)) ENDDO StdDevMVD1 => Wind_Data(1:Target_Number, 39) IF(.NOT.ds_put(STD_DEV_MVD1_LBL, StdDevMVD1, FUNC)) RETURN StdDevMVD2 => Wind_Data(1:Target_Number, 40) IF(.NOT.ds_put(STD_DEV_MVD2_LBL, StdDevMVD2, FUNC)) RETURN PctOfAvg1 => Wind_Data(1:Target_Number, 41) IF(.NOT.ds_put(PCT_OF_AVG1_LBL, PctOfAvg1, FUNC)) RETURN PctOfAvg2 => Wind_Data(1:Target_Number, 42) IF(.NOT.ds_put(PCT_OF_AVG2_LBL, PctOfAvg2, FUNC)) RETURN IF(.NOT.ds_shape_alloc(NUM_CLUSTERS1_LBL,Target_Number, NumClusters1, FUNC)) RETURN DO I = 1, Target_Number NumClusters1(I) = INT(Wind_Data(I, 43)) ENDDO IF(.NOT.ds_shape_alloc(MAX_CLUSTER_SIZE1_LBL,Target_Number, MaxClusterSize1, FUNC)) RETURN DO I = 1, Target_Number MaxClusterSize1(I) = INT(Wind_Data(I, 44)) ENDDO IF(.NOT.ds_shape_alloc(NUM_CLUSTERS2_LBL,Target_Number, NumClusters2, FUNC)) RETURN DO I = 1, Target_Number NumClusters2(I) = INT(Wind_Data(I, 45)) ENDDO IF(.NOT.ds_shape_alloc(MAX_CLUSTER_SIZE2_LBL,Target_Number, MaxClusterSize2, FUNC)) RETURN DO I = 1, Target_Number MaxClusterSize2(I) = INT(Wind_Data(I, 46)) ENDDO Altitude => Wind_Data(1:Target_Number, 47) IF(.NOT.ds_put(ALTITUDE_LBL, Altitude, FUNC)) RETURN IF(.NOT.ds_shape_alloc(LAND_FLAG_LBL,Target_Number, LandFlag, FUNC)) RETURN DO I = 1, Target_Number LandFlag(I) = INT(Wind_Data(I, 51)) ENDDO IF(.NOT.ds_shape_alloc(INVERSION_FLAG_LBL, Target_Number, InversionFlag, FUNC)) RETURN DO I = 1, Target_Number InversionFlag(I) = INT(Wind_Data(I, 52)) ENDDO IF(.NOT.ds_shape_alloc(CLOUD_PHASE_LBL,Target_Number, CloudPhase, FUNC)) RETURN DO I = 1, Target_Number CloudPhase(I) = INT(Wind_Data(I, 53)) ENDDO IF(.NOT.ds_shape_alloc(CLOUD_TYPE_LBL,Target_Number, CloudType, FUNC)) RETURN DO I = 1, Target_Number CloudType(I) = INT(Wind_Data(I, 54)) ENDDO TempGrad => Wind_Data(1:Target_Number, 57) IF(.NOT.ds_put(TEMP_GRAD_LBL, TempGrad, FUNC)) RETURN ShearPtr => Wind_Data(1:Target_Number, 58) IF(.NOT.ds_put(SHEAR_LBL, ShearPtr, FUNC)) RETURN MinCTP => Wind_Data(1:Target_Number, 59) IF(.NOT.ds_put(CTP_MIN_LBL, MinCTP, FUNC)) RETURN MaxCTP => Wind_Data(1:Target_Number, 60) IF(.NOT.ds_put(CTP_MAX_LBL, MaxCTP, FUNC)) RETURN MinCTT => Wind_Data(1:Target_Number, 61) IF(.NOT.ds_put(CTT_MIN_LBL, MinCTT, FUNC)) RETURN MaxCTT => Wind_Data(1:Target_Number, 62) IF(.NOT.ds_put(CTT_MAX_LBL, MaxCTT, FUNC)) RETURN MedianHgtErr => Wind_Data(1:Target_Number, 63) IF(.NOT.ds_put(HGT_ERR_MED_LBL, MedianHgtErr, FUNC)) RETURN MedianTempErr => Wind_Data(1:Target_Number, 64) IF(.NOT.ds_put(TEMP_ERR_MED_LBL, MedianTempErr, FUNC)) RETURN OrigFcstSpd => Wind_Data(1:Target_Number, 65) IF(.NOT.ds_put(ORIG_FCST_SPEED_LBL, OrigFcstSpd, FUNC)) RETURN OrigFcstDir => Wind_Data(1:Target_Number, 66) IF(.NOT.ds_put(ORIG_FCST_DIR_LBL, OrigFcstDir, FUNC)) RETURN BestFitPresLvl => Wind_Data(1:Target_Number, 67) IF(.NOT.ds_put(BEST_FIT_PRES_LVL_LBL, BestFitPresLvl, FUNC)) RETURN WghtCTP => Wind_Data(1:Target_Number, 68) IF(.NOT.ds_put(WGHT_CTP_LBL, WghtCTP, FUNC)) RETURN IF(.NOT.ds_shape_alloc(MAX_PCT1_LBL,Target_Number, MaxPct1, FUNC)) RETURN DO I = 1, Target_Number aValue = Wind_Data(I, 69) IF(aValue .NE. MISSING_VALUE_REAL4) THEN MaxPct1(I) = aValue*100.0 ELSE MaxPct1(I) = aValue ENDIF ENDDO IF(.NOT.ds_shape_alloc(MAX_PCT2_LBL, Target_Number, MaxPct2, FUNC)) RETURN DO I = 1, Target_Number aValue = Wind_Data(I, 70) IF(aValue .NE. MISSING_VALUE_REAL4) THEN MaxPct2(I) = aValue*100.0 ELSE MaxPct2(I) = aValue ENDIF ENDDO Min_OD => Wind_Data(1:Target_Number, 71) IF(.NOT.ds_put(MIN_OPTICAL_DEPTH_LBL, Min_OD, FUNC)) RETURN Max_OD => Wind_Data(1:Target_Number, 72) IF(.NOT.ds_put(MAX_OPTICAL_DEPTH_LBL, Max_OD, FUNC)) RETURN Median_OD => Wind_Data(1:Target_Number, 73) IF(.NOT.ds_put(MEDIAN_OPTICAL_DEPTH_LBL, Median_OD, FUNC)) RETURN Min_ACHA_COST => Wind_Data(1:Target_Number, 74) IF(.NOT.ds_put(MIN_ACHA_COST_LBL, Min_ACHA_COST, FUNC)) RETURN Max_ACHA_COST => Wind_Data(1:Target_Number, 75) IF(.NOT.ds_put(MAX_ACHA_COST_LBL, Max_ACHA_COST, FUNC)) RETURN Median_ACHA_COST => Wind_Data(1:Target_Number, 76) IF(.NOT.ds_put(MEDIAN_ACHA_COST_LBL, Median_ACHA_COST, FUNC)) RETURN Element => Wind_Data(1:Target_Number, 77) IF(.NOT.ds_put(ELEMENT_LBL, Element, FUNC)) RETURN Line => Wind_Data(1:Target_Number, 78) IF(.NOT.ds_put(LINE_LBL, Line, FUNC)) RETURN ! aab - Add CloudyPixels IF(.NOT.ds_shape_alloc(CLOUDY_PIXELS_LBL, Target_Number, CloudyPixels, FUNC)) RETURN DO I = 1, Target_Number CloudyPixels(I) = INT(Wind_Data(I, 82)) ENDDO ret = .TRUE. END FUNCTION PutTargetData END MODULE AMV_EN_Wind_Data_M