001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2017
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.adt;
030
031public class Intensity {
032    
033    private static int MWAnalysisFlag;
034    private static int Rule9StrengthFlag;
035
036    private static double[] BDCurve_Points = {
037        30.0, 9.0, -30.0, -42.0, -54.0, -64.0, -70.0, -76.0, -80.0, -84.0,
038        -100.0
039    };
040
041    public Intensity() {
042        MWAnalysisFlag = 0;
043        Rule9StrengthFlag = 0;
044    }
045    
046    /**
047     * Compute intensity values CI, Final T#, and Raw T#.
048     *
049     * @param RedoIntensityFlagValue Recalculate Intensity flag value.
050     * @param RunFullAnalysis Whether or not a full analysis should be
051     *                        performed.
052     * @param HistoryFileName Path to history file.
053     *
054     */
055    public static void CalculateIntensity(int RedoIntensityFlagValue,
056                                          boolean RunFullAnalysis,
057                                          String HistoryFileName)
058    {
059        double TnoRaw=0.0;
060        double TnoFinal=0.0;
061        double CI=0.0;
062        double CIadjP=0.0;
063        
064        boolean InitStrengthTF = Env.InitStrengthTF;
065        boolean LandFlagTF = Env.LandFlagTF;
066        
067        int RecLand = History.IRCurrentRecord.land;
068        double Latitude = History.IRCurrentRecord.latitude;
069        double Longitude = History.IRCurrentRecord.longitude;
070        
071        if((LandFlagTF)&&(RecLand==1)) {
072            /* Initialize Missing Record */
073            /* throw exception ?? */
074        } else {
075            double RetVal[] = adt_TnoRaw(RedoIntensityFlagValue,HistoryFileName);
076            TnoRaw = RetVal[0];
077            MWAnalysisFlag = (int)RetVal[1];
078            /* System.out.printf("RawT#Adj=%f  MWAnalysisFlag=%d\n",TnoRaw,MWAnalysisFlag); */
079            History.IRCurrentRecord.Traw = TnoRaw;
080        }
081        
082        /* System.out.printf("RunFullAnalysis=%b\n",RunFullAnalysis); */
083        if(!RunFullAnalysis) {
084            /* Perform Spot Analysis (only T#raw) */
085            History.IRCurrentRecord.Tfinal = TnoRaw;
086            History.IRCurrentRecord.CI = TnoRaw;
087            //CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,TnoRaw,Latitude,Longitude);
088            CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,Latitude,Longitude);
089            History.IRCurrentRecord.CIadjp = CIadjP;
090            History.IRCurrentRecord.rule9 = 0;
091        } else {
092            int NumRecsHistory = History.HistoryNumberOfRecords();
093            /* System.out.printf("numrecs=%d  inistrength=%b historyfilename=%s*\n",NumRecsHistory,InitStrengthTF,HistoryFileName); */
094            /* System.out.printf("MWanalysisflag=%d\n",MWAnalysisFlag); */
095            if((((NumRecsHistory==0)&&(InitStrengthTF))&&(HistoryFileName!=null))||(MWAnalysisFlag==1)) {
096                System.out.printf("tnoraw=%f\n",TnoRaw);
097                History.IRCurrentRecord.Tfinal = TnoRaw;
098                History.IRCurrentRecord.CI = TnoRaw;
099                History.IRCurrentRecord.CIadjp = 0.0;
100                if(MWAnalysisFlag==1) {
101                    double[] RetVals = adt_CIno(HistoryFileName);
102                    CI = RetVals[0];
103                    Rule9StrengthFlag = (int)RetVals[1];
104                    History.IRCurrentRecord.CI = CI;
105                    History.IRCurrentRecord.rule9 = Rule9StrengthFlag;
106                    //CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,TnoRaw,Latitude,Longitude);
107                    CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,Latitude,Longitude);
108                    History.IRCurrentRecord.CIadjp = CIadjP;
109                } else {
110                    History.IRCurrentRecord.CI = TnoRaw;
111                    History.IRCurrentRecord.rule9 = 0;
112                }
113            } else {
114                /* System.out.printf("rawt=%f\n",History.IRCurrentRecord.Traw); */
115                TnoFinal = adt_TnoFinal(1);
116                /* System.out.printf("FinalT#=%f\n",TnoFinal); */
117                History.IRCurrentRecord.Tfinal = TnoFinal;
118                double[] RetVals2 = adt_CIno(HistoryFileName);
119                CI = RetVals2[0];
120                Rule9StrengthFlag = (int)RetVals2[1];
121                /* System.out.printf("CI#=%f Rule9StrengthFlag=%d \n",CI,Rule9StrengthFlag); */
122                History.IRCurrentRecord.CI = CI;
123                History.IRCurrentRecord.rule9 = Rule9StrengthFlag;
124            }
125        }
126    }
127    
128    /**
129     * Compute initial Raw T-Number value using original Dvorak rules
130     *
131     * @param RedoIntensityFlag Recalculate Intensity flag value.
132     * @param HistoryFileName Path to history file.
133     *
134     * @return Array of two doubles. First value represents
135     * intensity estimate, and the second is the analysis flag.
136     */
137    public static double[] adt_TnoRaw(int RedoIntensityFlag,
138                                      String HistoryFileName)
139    {
140        int XInc;
141        int CloudBDCategory = 0;
142        int Rule8AdjCatValue = 0;
143        int PreviousHistoryRecPtr = 0;
144        double CloudTnoIntensity = -909.0;
145        double TnoRawValue=0.0;
146        double IntensityEstimateValue = 0.0;
147        double TnoInterpAdjValue = 0.0;
148        double FinalIntensityEstimateValue = 0.0;
149        double ShearInterpAdjValue = 0.0;
150        double CDOSizeRegressionAdjValue = 0.0;
151        double EyeCloudTempDifferenceAdjValue = 0.0;
152        double CDOSymmatryRegressionAdjValue = 0.0;
153        double PreviousHistoryCIValue = 0.0;
154        double CIValueAdjustmentFactorValue=0.0;
155        double HistoryRecTime = 0.0;
156        boolean First48HourShearTF = false;
157        boolean MWOFFTF = false;
158        boolean LandCheckTF = true;
159        
160        /* EYE SCENE REGRESSION BASE VALUES */
161        double[][] EyeRegressionBaseArray =
162        /*                      DG   MG   LG   B    W    CMG  CDG           */
163                    {{1.00,2.00,3.25,4.00,4.75,5.25,5.75,6.50,7.25,7.75,8.25},
164                     {1.50,2.25,3.30,3.85,4.50,4.75,5.15,5.50,6.00,6.25,6.75}};
165        /* CLOUD SCENE REGRESSION BASE VALUES */
166        double[][] CloudRegressionBaseArray =
167        /*                      DG   MG   LG   B    W    CMG  CDG           */
168                    {{2.00,2.40,3.25,3.50,3.75,4.00,4.10,4.20,4.30,4.40,4.70},
169                     {2.05,2.40,3.00,3.20,3.40,3.55,3.65,3.75,3.80,3.90,4.10}};
170        /* Curved Band Scene Type Intensity Values (each 20% of wrap around center) */
171        double[] CurvedBandIntensityArray = {1.5,1.5,2.0,2.5,3.0,3.5,4.0};
172        /* Shear Scene Type Distance Threshold Values (distance in km) */
173        double[] ShearDistanceArray = {0.0,35.0,50.0,80.0,110.0,140.0};
174        /* Shear Scene Type Intensity Values */
175        double[] ShearIntensityArray = {3.50,3.00,2.50,2.25,2.00,1.50};
176        
177        /* Rule 8 Adjustments
178         *  Row 1 - Shear Scenes (original rule 8)
179         *  Row 2 - Eye Scenes (original + 0.5)
180         *  Row 3 - Other Scenes (original - 0.5)
181         */
182        double[][] Rule8AdjArray =
183        /*                1hr  6hr 12hr 18hr 24hr                           */
184                    {{0.0,0.51,1.01,1.71,2.21,2.71,0.0,0.0,0.21,0.51},
185                     {0.0,0.51,1.01,2.71,3.21,3.71,1.31,0.0,0.21,0.51},
186                     {0.0,0.51,0.71,1.21,1.71,2.21,0.0,0.0,0.21,0.51}};
187        /* Eye Regression Factor (Atlantic, Pacific) */
188        double[] EyeCloudTempDifferenceRegressionFactorArrayEYE = { 0.011, 0.015 };
189        /* Cloud Region Symmatry Regression Factor - Eye Scene (Atlantic, Pacific) */
190        double[] CloudSymmatryRegressionFactorArrayEYE = { -0.015, -0.015 };
191        /* CDO size (km - Dark Gray BD Curve) - Cloud Scene (Atlantic, Pacific) */
192        double[] CDOSizeRegressionFactorArrayCLD = { 0.002 , 0.001 };
193        /* Cloud Region Symmatry Regression Factor - Cloud Scene (Atlantic, Pacific) */
194        double[] CloudSymmatryRegressionFactorArrayCLD = { -0.030, -0.015 };
195        
196        double CurrentTime = 1900001.0;
197        int ImageDate = 1900001;
198        int ImageTime = 000000;;
199        int RecDate = 1900001;
200        int RecTime = 000000;
201        int RecLand = 0;
202        boolean LandFlagTF = Env.LandFlagTF;
203        boolean InitStrengthTF = Env.InitStrengthTF;
204        double InitStrengthValue = Env.InitRawTValue;
205        int LandFlagCurrent = History.IRCurrentRecord.land;
206        double RecTnoRaw = 0.0;
207        
208        int NumRecsHistory = History.HistoryNumberOfRecords();
209        /* System.out.printf("numrecs=%d\n",NumRecsHistory); */
210        if((NumRecsHistory==0)&&(HistoryFileName!=null)) {
211            /*
212             * History file does not exist and current analysis is
213             * first analysis for the storm
214             */
215            if(InitStrengthTF) {
216               History.IRCurrentRecord.TrawO = InitStrengthValue;
217               return new double [] { InitStrengthValue, 0.0 };                      /* EXIT */
218            }
219        } else {
220            double LastValidRecordTime=1900001.0;
221            ImageDate = History.IRCurrentRecord.date;
222            ImageTime = History.IRCurrentRecord.time;
223            CurrentTime = Functions.calctime(ImageDate,ImageTime);
224            /* System.out.printf("CurrentTime=%f\n",CurrentTime); */
225            double FirstHistoryRecTime = LastValidRecordTime;
226            if(NumRecsHistory!=0) {
227                RecDate = History.HistoryFile[0].date;
228                RecTime = History.HistoryFile[0].time;
229                FirstHistoryRecTime = Functions.calctime(RecDate,RecTime);
230                if((CurrentTime-FirstHistoryRecTime)<=2.0) {
231                    First48HourShearTF = true;
232                }
233            } else {
234                FirstHistoryRecTime = LastValidRecordTime;
235            }
236            
237            /* System.out.printf("FirstHistoryRecTime=%f\n",FirstHistoryRecTime); */
238            XInc = 0;
239            while(XInc<NumRecsHistory) {
240                RecDate = History.HistoryFile[XInc].date;
241                RecTime = History.HistoryFile[XInc].time;
242                HistoryRecTime = Functions.calctime(RecDate,RecTime);
243                /* System.out.printf("XInc= %d  HistoryRecTime%f\n",XInc,HistoryRecTime); */
244                if(HistoryRecTime>CurrentTime) {
245                   break;
246                }
247                RecLand = History.HistoryFile[XInc].land;
248                RecTnoRaw = History.HistoryFile[XInc].Traw;
249                LandCheckTF = true;
250                if(((LandFlagTF)&&(RecLand==1))||(RecTnoRaw<1.0)) {
251                    LandCheckTF = false;
252                }
253                if(LandCheckTF) {
254                    if((HistoryRecTime==CurrentTime)&&(XInc==0)&&(InitStrengthValue!=0.0)) {
255                        /*
256                         * Current analysis is at or before first record in
257                         * existing history file - return global initial
258                         * strength value
259                         */
260                        System.out.printf("FIRST RECORD in NON-empty file\n");
261                        History.IRCurrentRecord.TrawO = InitStrengthValue;
262                        /* InitStrengthValue = 0.0; */
263                        /* Env.InitRawTValue = 0.0; */
264                        return new double[] {InitStrengthValue, 0.0 };  /* EXIT */
265                    }
266                    PreviousHistoryRecPtr = XInc;
267                    LastValidRecordTime = HistoryRecTime;
268                }
269                XInc++;
270            }
271            if(HistoryFileName!=null) {
272                PreviousHistoryCIValue = History.HistoryFile[PreviousHistoryRecPtr].CI;
273            } else {
274                PreviousHistoryCIValue = 4.0;
275            }
276            
277            /* System.out.printf("PreviousHistoryCIValue=%f\n",PreviousHistoryCIValue); */
278            if(((CurrentTime-LastValidRecordTime)>1.0)&& (HistoryFileName!=null)) {
279                /* The history file either begins with all land scenes
280                 * or there is a break in the history file of greater than
281                 * 24 hours.  Reinitialize the storm with the input
282                 * Initial Classification value
283                 */
284                History.IRCurrentRecord.TrawO = InitStrengthValue;
285                Env.InitRawTValue = -1.0;
286                /* System.out.printf("returning...\n"); */
287                return new double[] { InitStrengthValue, 0.0 };  /* EXIT */
288            }
289        }
290        
291        double CloudTemperatureCurrent = History.IRCurrentRecord.cloudt;
292        double EyeTemperatureCurrent = History.IRCurrentRecord.eyet;
293        
294        /* System.out.printf("current cloudT=%f  eyeT=%f\n",CloudTemperatureCurrent,EyeTemperatureCurrent); */
295        for(XInc=0;XInc<10;XInc++) {
296            /* compute cloud category */
297            if((CloudTemperatureCurrent<=BDCurve_Points[XInc])&& (CloudTemperatureCurrent>BDCurve_Points[XInc+1])) {
298                CloudBDCategory = XInc;
299                CloudTnoIntensity = (CloudTemperatureCurrent-BDCurve_Points[CloudBDCategory])/
300                                    (BDCurve_Points[CloudBDCategory+1]-
301                                     BDCurve_Points[CloudBDCategory]);
302            }
303            /* compute eye category for eye adjustment */
304            if((EyeTemperatureCurrent<=BDCurve_Points[XInc])&& (EyeTemperatureCurrent>BDCurve_Points[XInc+1])) {
305            }
306        }
307        
308        /* System.out.printf("cloudBD=%d  CloudTnoIntensity= %f eyeBD=%d  \n",CloudBDCategory,CloudTnoIntensity,EyeBDCategory); */
309        int EyeSceneCurrent = History.IRCurrentRecord.eyescene;
310        if(EyeSceneCurrent==1) {
311            /* this matches DT used at NHC (jack beven) */
312            /* EyeTemperature=(9.0+EyeTemperature)/2.0; */
313            /* Eye Temp is between +9C (beven) and measured eye temp (turk) */
314            EyeTemperatureCurrent = (EyeTemperatureCurrent+9.0)/2.0;
315            History.IRCurrentRecord.eyet = EyeTemperatureCurrent;
316        }
317        
318        /* System.out.printf("EyeCloudBDCategoryDifference=%f\n",EyeCloudBDCategoryDifference); */
319        
320        /* if scenetype is EYE */
321        int CurvedBandBDAmountCurrent = History.IRCurrentRecord.ringcbval;
322        int CurvedBandBDCategoryCurrent = History.IRCurrentRecord.ringcb;
323        double MWScoreValueCurrent = History.IRCurrentRecord.mwscore;
324        /* System.out.printf("MWScoreValueCurrent=%f\n",MWScoreValueCurrent); */
325        
326        MWAnalysisFlag = 0;
327        if(RedoIntensityFlag==1) {
328            Env.MWJulianDate = History.IRCurrentRecord.mwdate;
329            Env.MWHHMMSSTime = History.IRCurrentRecord.mwtime;
330            System.out.printf("****REDO : MW DATE=%d Time=%d\n", Env.MWJulianDate, Env.MWHHMMSSTime);
331        }
332        
333        int CloudScene = History.IRCurrentRecord.cloudscene;
334        int EyeScene = History.IRCurrentRecord.eyescene;
335        int DomainID = Env.DomainID;
336        double CloudSymAveCurrent = History.IRCurrentRecord.cloudsymave;
337        double EyeCDOSizeCurrent = History.IRCurrentRecord.eyecdosize;
338        /* System.out.printf("CloudScene=%d\n",CloudScene); */
339        if(CloudScene==3) {
340            /* CURVED BAND */
341            CurvedBandBDAmountCurrent = Math.min(30,CurvedBandBDAmountCurrent+1);
342            int CurvedBandBDPercentage = CurvedBandBDAmountCurrent/5;
343            double IncrementMultFactor = 0.1;
344            if(CurvedBandBDPercentage==1) {
345                IncrementMultFactor = 0.2;
346            }
347            IntensityEstimateValue=CurvedBandIntensityArray[CurvedBandBDPercentage];
348            TnoInterpAdjValue = IncrementMultFactor*
349                                ((double)(CurvedBandBDAmountCurrent-(CurvedBandBDPercentage*5)));
350            /*
351             * System.out.printf("CurvedBandBDAmount=%d  CurvedBandBDPercentage=%d CurvedBandBDCategory=%d  IntensityEstimateValue=%f TnoInterpAdjValue=%f\n",
352             *         CurvedBandBDAmountCurrent,CurvedBandBDPercentage, CurvedBandBDCategoryCurrent,IntensityEstimateValue, TnoInterpAdjValue);
353             */
354            IntensityEstimateValue = IntensityEstimateValue+TnoInterpAdjValue;
355            if(CurvedBandBDCategoryCurrent==5) {
356                IntensityEstimateValue = Math.min(4.0,IntensityEstimateValue+0.5);
357            }
358            if(CurvedBandBDCategoryCurrent==6) {
359                IntensityEstimateValue = Math.min(4.5,IntensityEstimateValue+1.0);
360            }
361            Rule8AdjCatValue=2;
362        } else if(CloudScene==4) {
363            /* POSSIBLE SHEAR -- new definition from NHC */
364            XInc = 0;
365            IntensityEstimateValue = 1.5;
366            double ShearDistanceCurrent = History.IRCurrentRecord.eyecdosize;
367            while(XInc<5) {
368                if((ShearDistanceCurrent>=ShearDistanceArray[XInc])&& (ShearDistanceCurrent<ShearDistanceArray[XInc+1])) {
369                    ShearInterpAdjValue = (ShearDistanceCurrent-ShearDistanceArray[XInc])/
370                                          (ShearDistanceArray[XInc+1]-
371                                           ShearDistanceArray[XInc]);
372                    TnoInterpAdjValue = (ShearInterpAdjValue*
373                                        (ShearIntensityArray[XInc+1]-
374                                         ShearIntensityArray[XInc]));
375                    IntensityEstimateValue = ShearIntensityArray[XInc]+TnoInterpAdjValue;
376                    XInc=5;
377                } else {
378                    XInc++;
379                }
380            }
381            Rule8AdjCatValue = 0;
382            if(First48HourShearTF) {
383                IntensityEstimateValue=Math.min(2.5,IntensityEstimateValue);
384                if(Env.DEBUG==100) {
385                    System.out.printf("Constraining SHEAR Intensity to 2.5 or less during first 48 hours\n");
386                }
387            }
388        } else {
389            /* EYE or NO EYE */
390            /* int DomainID_Local = Env.DomainID = DomainID; */
391            if(EyeScene<=2) {
392                /* EYE */
393                /*
394                 * System.out.printf("EYE : EyeTemperature=%f  CloudTemperature=%f\n",
395                 *         EyeTemperatureCurrent,CloudTemperatureCurrent);
396                 * System.out.printf("EYE : CloudTnoIntensity=%f  DomainID=%d CloudBDCategory=%d\n",CloudTnoIntensity,DomainID,
397                 *         CloudBDCategory);
398                 */
399                TnoInterpAdjValue = (CloudTnoIntensity*
400                        (EyeRegressionBaseArray[DomainID][CloudBDCategory+1]-
401                         EyeRegressionBaseArray[DomainID][CloudBDCategory]));
402                EyeCloudTempDifferenceAdjValue =
403                        EyeCloudTempDifferenceRegressionFactorArrayEYE[DomainID]*
404                        (EyeTemperatureCurrent-CloudTemperatureCurrent);
405                CDOSymmatryRegressionAdjValue =
406                        CloudSymmatryRegressionFactorArrayEYE[DomainID]*
407                        (CloudSymAveCurrent);
408                        
409                /* System.out.printf("EYE : cloudsymave=%f  CDOSymmatryRegressionAdjValue=%f\n",
410                          CloudSymAveCurrent,CDOSymmatryRegressionAdjValue); */
411                        
412                IntensityEstimateValue =
413                        EyeRegressionBaseArray[DomainID][CloudBDCategory]+
414                        TnoInterpAdjValue+
415                        EyeCloudTempDifferenceAdjValue+
416                        CDOSymmatryRegressionAdjValue;
417                        
418                /* System.out.printf("EYE :TnoInterpAdjValue=%f EyeCloudTempDifferenceAdjValue=%f CDOSymmatryRegressionAdjValue=%f IntensityEstimateValue=%f\n",
419                          TnoInterpAdjValue,EyeCloudTempDifferenceAdjValue, CDOSymmatryRegressionAdjValue,IntensityEstimateValue); */
420                        
421                IntensityEstimateValue = Math.min(IntensityEstimateValue,9.0);
422                /* System.out.printf("IntensityEstimateValue=%f\n",IntensityEstimateValue); */
423                if(EyeScene==2)  {
424                    /* LARGE EYE adjustment */
425                    IntensityEstimateValue = Math.min(IntensityEstimateValue-0.5,6.5);
426                }
427                Rule8AdjCatValue = 1;
428            } else {
429                /* NO EYE */
430                /* CDO */
431                TnoInterpAdjValue = (CloudTnoIntensity*
432                        (CloudRegressionBaseArray[DomainID][CloudBDCategory+1]-
433                         CloudRegressionBaseArray[DomainID][CloudBDCategory]));
434                CDOSizeRegressionAdjValue =
435                        CDOSizeRegressionFactorArrayCLD[DomainID]*
436                        EyeCDOSizeCurrent;
437                
438                /* System.out.printf("CDO : dgraysize=%f  CDOSymmatryRegressionAdjValue=%f\n",
439                          EyeCDOSizeCurrent,CDOSizeRegressionAdjValue); */
440                 
441                CDOSymmatryRegressionAdjValue =
442                        CloudSymmatryRegressionFactorArrayCLD[DomainID]*
443                        (CloudSymAveCurrent);
444                
445                /* System.out.printf("CDO : cloudsymave=%f  CDOSymmatryRegressionAdjValue=%f\n",
446                          CloudSymAveCurrent,CDOSymmatryRegressionAdjValue); */
447                 
448                IntensityEstimateValue =
449                        CloudRegressionBaseArray[DomainID][CloudBDCategory]+
450                        TnoInterpAdjValue+CDOSizeRegressionAdjValue+CDOSymmatryRegressionAdjValue;
451                IntensityEstimateValue = IntensityEstimateValue-0.1; /* bias adjustment */
452                /* CDO adjustment for very weak or very strong CDOs */
453                if(CloudScene==0) {
454                    CIValueAdjustmentFactorValue=0.0;
455                    if(PreviousHistoryCIValue>=4.5) {
456                       CIValueAdjustmentFactorValue = Math.max(0.0,Math.min(1.0,PreviousHistoryCIValue-4.5));
457                    }
458                    if(PreviousHistoryCIValue<=3.0) {
459                       CIValueAdjustmentFactorValue = Math.min(0.0,Math.max(-1.0,PreviousHistoryCIValue-3.0));
460                    }
461                    IntensityEstimateValue = IntensityEstimateValue+CIValueAdjustmentFactorValue;
462                }
463                
464                /* System.out.printf("CDO : TnoInterpAdjValue=%f CDOSizeRegressionAdjValue=%f CDOSymmatryRegressionAdjValue=%f IntensityEstimateValue=%f\n",
465                          TnoInterpAdjValue,CDOSizeRegressionAdjValue,CDOSymmatryRegressionAdjValue,IntensityEstimateValue); */
466                 
467                CIValueAdjustmentFactorValue = 0.0;
468                /* EMBEDDED CENTER */
469                if(CloudScene==1) {
470                    CIValueAdjustmentFactorValue = Math.max(0.0,Math.min(
471                                                 1.5,PreviousHistoryCIValue-4.0));
472                    
473                    /* System.out.printf("EMBC : PreviousHistoryCIValue=%f TnoInterpAdjValue=%f\n",
474                              PreviousHistoryCIValue,CIValueAdjustmentFactorValue); */
475                     
476                    IntensityEstimateValue = IntensityEstimateValue+CIValueAdjustmentFactorValue;
477                }
478                /* IRREGULAR CDO (PT=3.5) */
479                if(CloudScene==2) {
480                    /* additional IrrCDO bias adjustment */
481                    IntensityEstimateValue = IntensityEstimateValue+0.3;
482                    IntensityEstimateValue = Math.min(3.5,Math.max(2.5,IntensityEstimateValue));
483                }
484                Rule8AdjCatValue = 2;
485            }
486        }
487        
488        FinalIntensityEstimateValue = ((double)((int)((IntensityEstimateValue+0.01)*10.0)))/10.0;
489        History.IRCurrentRecord.TrawO = FinalIntensityEstimateValue;
490        
491        /* System.out.printf("RawT#orig=%f\n",FinalIntensityEstimateValue); */
492        
493        /* NEW Microwave Eye Score logic */
494        if(Env.DEBUG==100) {
495            System.out.printf("***IntensityEstimateValue=%f\n",IntensityEstimateValue);
496        }
497        
498        /* moved MW analysis here to work with all scenes */
499        
500        double[] RetVals2 = MWAdj.adt_calcmwadjustment(MWScoreValueCurrent,FinalIntensityEstimateValue);
501        MWAnalysisFlag = (int)RetVals2[0];
502        IntensityEstimateValue = RetVals2[1];
503        
504        if(Env.DEBUG==100) {
505            System.out.printf("MWAnalysisFlag=%d  IntensityEstimateValue=%f\n", MWAnalysisFlag,IntensityEstimateValue);
506        }
507        FinalIntensityEstimateValue=(double)((int)((IntensityEstimateValue+0.01)*10.0))/10.0;
508        /* System.out.printf("FinalIntensityEstimateValue=%f\n",FinalIntensityEstimateValue); */
509        
510        int Rule8Current = History.IRCurrentRecord.rule8;
511        
512        if(Rule8Current==34) MWOFFTF = true;
513        
514        boolean SpecialPostMWRule8EYEFlag = false;
515        if((MWOFFTF)&&(Rule8AdjCatValue==1)) {
516            /* System.out.printf("USING NEW POST-MW EYE RULE 8 CONSTRAINTS!!!\n"); */
517            SpecialPostMWRule8EYEFlag = true;
518        }
519        
520        /* System.out.printf("MWAnalysisFlag=%d\n",MWAnalysisFlag); */
521        if(MWAnalysisFlag==0) {
522            /*
523             * perform Dvorak EIR Rule 8 Constrants on Raw T# value
524             * "velden rule" (actually 86.4 minutes... 0.06 of a day)
525             * "additional velden rule", only over first 6 hours
526             * All cases     : delT of 0.5 over  1 hour  : rule8 = 9 "velden rule"
527             *                 delT of 0.1 over  1 hour  : rule8 = 8 "additional"
528             * Raw T# <  4.0 : delT of 1.0 over  6 hours : rule8 = 2
529             *                 No threshold exceeded     : rule8 = 0
530             * Raw T# >= 4.0 : delT of 1.0 over  6 hours : rule8 = 2
531             *                 delT of 1.5 over 12 hours : rule8 = 3
532             *                 delT of 2.0 over 18 hours : rule8 = 4
533             *                 delT of 2.5 over 24 hours : rule8 = 5
534             *                 No threshold exceeded     : rule8 = 0
535             */
536            double PreviousHistoryFinalTnoValue = FinalIntensityEstimateValue;
537            int EyeSceneCounter = 0;
538            int NonEyeSceneCounter = 0;
539            double TnoValueMinus1hr = FinalIntensityEstimateValue;
540            double TnoValueMinus6hr = FinalIntensityEstimateValue;
541            double TnoValueMinus12hr = FinalIntensityEstimateValue;
542            double TnoValueMinus18hr = FinalIntensityEstimateValue;
543            double TnoValueMinus24hr = FinalIntensityEstimateValue;
544            double RawTnoValueMinus6hrTime = CurrentTime;
545            double RawTnoValueMinus6hr = FinalIntensityEstimateValue;
546            double RawTnoValueMinus1hr = FinalIntensityEstimateValue;
547            boolean First6hrRecordTF = false;
548            if(NumRecsHistory!=0) {
549                /*
550                 * 0.0416 is one hour... round to 0.05 to make sure I catch the
551                 * hour previous report
552                 */
553                double CurrentTimeMinus1hr = CurrentTime-0.05;
554                double CurrentTimeMinus6hr = CurrentTime-0.26;
555                double CurrentTimeMinus12hr = CurrentTime-0.51;
556                double CurrentTimeMinus18hr = CurrentTime-0.76;
557                double CurrentTimeMinus24hr = CurrentTime-1.01;
558                double TnoDifferenceValueMinus1hr;
559                double TnoDifferenceValueMinus6hr;
560                double TnoDifferenceValueMinus12hr;
561                double TnoDifferenceValueMinus18hr;
562                double TnoDifferenceValueMinus24hr;
563                RecDate = History.HistoryFile[0].date;
564                RecTime = History.HistoryFile[0].time;
565                double FirstHistoryRecTime = Functions.calctime(RecDate,RecTime);
566                boolean FirstHistoryLandRecTF = true;
567                boolean CurrentTimeMinus24hrTF = false;
568                boolean CurrentTimeMinus18hrTF = false;
569                boolean CurrentTimeMinus12hrTF = false;
570                boolean CurrentTimeMinus6hrTF = false;
571                boolean CurrentTimeMinus1hrTF = false;
572                boolean HistoryVeldenRuleFlagTF = false;
573                boolean ApplyVeldenRuleTF = true;
574                double RecTFinal;
575                double RecTRaw;
576                int RecRule9;
577                int RecRapidDiss;
578                int RecEyeScene;
579                int Rule8Val = 0;
580                int PreviousHistoryRule9Value = 0;
581                int PreviousHistoryRapidDissIDValue = 0;
582                double Rule8TESTValue;
583                
584                if(FirstHistoryRecTime>=CurrentTimeMinus6hr) {
585                    First6hrRecordTF = true;
586                }
587                XInc = 0;
588                while(XInc<NumRecsHistory) {
589                    RecDate = History.HistoryFile[XInc].date;
590                    RecTime = History.HistoryFile[XInc].time;
591                    RecLand = History.HistoryFile[XInc].land;
592                    HistoryRecTime = Functions.calctime(RecDate,RecTime);
593                    RecTFinal = History.HistoryFile[XInc].Tfinal;
594                    RecTRaw = History.HistoryFile[XInc].Traw;
595                    RecRule9 = History.HistoryFile[XInc].rule9;
596                    RecRapidDiss = History.HistoryFile[XInc].rapiddiss;
597                    RecEyeScene = History.HistoryFile[XInc].eyescene;
598                    /* System.out.printf("currenttime=%f  historyrectime=%f\n",CurrentTime,HistoryRecTime); */
599                    if(HistoryRecTime>=CurrentTime) {
600                       /* System.out.printf("outta here\n"); */
601                       break;
602                    }
603                    LandCheckTF = true;
604                    /* System.out.printf("**RecLand=%d\n",RecLand); */
605                    if(((LandFlagTF)&&(RecLand==1))||(RecTnoRaw<1.0)) {
606                        LandCheckTF = false;
607                        if (FirstHistoryLandRecTF) {
608                            FirstHistoryLandRecTF = false;
609                        }
610                    } else {
611                        FirstHistoryLandRecTF = true;
612                    }
613                    /* System.out.printf("**LandCheckTF=%b\n",LandCheckTF); */
614                    if((HistoryRecTime>=CurrentTimeMinus24hr)&& (HistoryRecTime<CurrentTime)&& (!CurrentTimeMinus24hrTF)&&(LandCheckTF)) {
615                        CurrentTimeMinus24hrTF = true;
616                        TnoValueMinus24hr = RecTFinal;
617                    }
618                    if((HistoryRecTime>=CurrentTimeMinus18hr)&& (HistoryRecTime<CurrentTime)&& (!CurrentTimeMinus18hrTF)&&(LandCheckTF)) {
619                        CurrentTimeMinus18hrTF = true;
620                        TnoValueMinus18hr = RecTFinal;
621                    }
622                    if((HistoryRecTime>=CurrentTimeMinus12hr)&& (HistoryRecTime<CurrentTime)&& (!CurrentTimeMinus12hrTF)&&(LandCheckTF)) {
623                        CurrentTimeMinus12hrTF = true;
624                        TnoValueMinus12hr = RecTFinal;
625                    }
626                    if((HistoryRecTime>=CurrentTimeMinus6hr)&& (HistoryRecTime<CurrentTime)&& (!CurrentTimeMinus6hrTF)&&(LandCheckTF)) {
627                        CurrentTimeMinus6hrTF = true;
628                        TnoValueMinus6hr = RecTFinal;
629                        RawTnoValueMinus6hr = RecTRaw;
630                        RawTnoValueMinus6hrTime = HistoryRecTime;
631                    }
632                    if((HistoryRecTime>=CurrentTimeMinus1hr)&& (HistoryRecTime<CurrentTime)&& (!CurrentTimeMinus1hrTF)&&(LandCheckTF)) {
633                        CurrentTimeMinus1hrTF = true;
634                        TnoValueMinus1hr = RecTFinal;
635                        RawTnoValueMinus1hr = RecTRaw;
636                    }
637                    if((HistoryRecTime<CurrentTime)&&(LandCheckTF)) {
638                        PreviousHistoryFinalTnoValue = RecTFinal;
639                        PreviousHistoryRule9Value = RecRule9;
640                        PreviousHistoryRapidDissIDValue = RecRapidDiss;
641                        if(RecEyeScene<=2) {
642                            EyeSceneCounter++;
643                            NonEyeSceneCounter = 0;
644                            if(EyeSceneCounter>=3||HistoryVeldenRuleFlagTF) {
645                                ApplyVeldenRuleTF = false;
646                                HistoryVeldenRuleFlagTF = true;
647                            }
648                        } else {
649                            EyeSceneCounter = 0;
650                            NonEyeSceneCounter++;
651                            if(NonEyeSceneCounter>=3) {
652                               ApplyVeldenRuleTF = true;
653                               HistoryVeldenRuleFlagTF = false;
654                            }
655                        }
656                        if(PreviousHistoryRapidDissIDValue>=2) {
657                            ApplyVeldenRuleTF = false;
658                        }
659                    }
660                    XInc++;
661                }
662                
663                /* System.out.printf("LandFlagCurrent=%d\n",LandFlagCurrent); */
664                /* added to correctly analyze current record (08/27/13)*/
665                if(LandFlagCurrent==2) {
666                    if(EyeScene<=2) {
667                        if(EyeSceneCounter>=2||HistoryVeldenRuleFlagTF) {
668                            ApplyVeldenRuleTF = false;
669                        }
670                    } else {
671                        ApplyVeldenRuleTF = true;
672                    }
673                }
674                /* System.out.printf("ApplyVeldenRuleTF=%b\n",ApplyVeldenRuleTF); */
675                Rule8Val = (Rule8AdjCatValue*10)+0;
676                /* System.out.printf("Rule8AdjCatValue=%d Rule8Val=%d\n",Rule8AdjCatValue,Rule8Val); */
677                History.IRCurrentRecord.rule8 = Rule8Val;
678                /* System.out.printf("PreviousHistoryFinalTnoValue=%f\n",PreviousHistoryFinalTnoValue); */
679                /* System.out.printf("Rule8 value = %d\n",History.IRCurrentRecord.rule8); */
680                if(PreviousHistoryFinalTnoValue<4.0) {
681                    /* System.out.printf(" LESS THAN 4.0\n"); */
682                    /* Raw T# < 4.0 */
683                    /* System.out.printf("First6hrRecordTF=%b\n",First6hrRecordTF); */
684                    if(First6hrRecordTF) {
685                        if(CurrentTimeMinus1hrTF) {
686                            TnoDifferenceValueMinus1hr = Math.abs(RawTnoValueMinus1hr-
687                                                     FinalIntensityEstimateValue);
688                            if(TnoDifferenceValueMinus1hr> Rule8AdjArray[Rule8AdjCatValue][8]) {
689                                FinalIntensityEstimateValue = Math.max((RawTnoValueMinus1hr-
690                                                      Rule8AdjArray[Rule8AdjCatValue][8]),
691                                                      Math.min((RawTnoValueMinus1hr+
692                                                      Rule8AdjArray[Rule8AdjCatValue][8]),
693                                                      FinalIntensityEstimateValue));
694                                Rule8Val = (Rule8AdjCatValue*10)+8;
695                                History.IRCurrentRecord.rule8 = Rule8Val;
696                            }
697                        } else {
698                            /*
699                            **  no value available within past hour...
700                            ** must determine approx value
701                            */
702                            TnoDifferenceValueMinus1hr = 0.1*(Math.abs(CurrentTime-RawTnoValueMinus6hrTime)/.0416);
703                            double RawTnoMinimumValue = RawTnoValueMinus6hr - TnoDifferenceValueMinus1hr;
704                            double RawTnoMaximumValue = RawTnoValueMinus6hr + TnoDifferenceValueMinus1hr;
705                            if((FinalIntensityEstimateValue>RawTnoMaximumValue)|| (FinalIntensityEstimateValue<RawTnoMinimumValue)) {
706                                FinalIntensityEstimateValue = Math.max(RawTnoMinimumValue,
707                                                      Math.min(RawTnoMaximumValue,
708                                                      FinalIntensityEstimateValue));
709                                Rule8Val = (Rule8AdjCatValue*10)+8;
710                                History.IRCurrentRecord.rule8 = Rule8Val;
711                            }
712                        }
713                    } else {
714                        TnoDifferenceValueMinus1hr = Math.abs(TnoValueMinus1hr-
715                                                         FinalIntensityEstimateValue);
716                        /* System.out.printf("TnoDifferenceValueMinus1hr=%f\n",TnoDifferenceValueMinus1hr); */
717                        if((TnoDifferenceValueMinus1hr> Rule8AdjArray[Rule8AdjCatValue][9])&& (CurrentTimeMinus1hrTF)&&(ApplyVeldenRuleTF)) {
718                            FinalIntensityEstimateValue = Math.max(TnoValueMinus1hr-
719                                                     Rule8AdjArray[Rule8AdjCatValue][9],
720                                                     Math.min(TnoValueMinus1hr+
721                                                     Rule8AdjArray[Rule8AdjCatValue][9],
722                                                     FinalIntensityEstimateValue));
723                            Rule8Val = (Rule8AdjCatValue*10)+9;
724                            History.IRCurrentRecord.rule8 = Rule8Val;
725                        }
726                        TnoDifferenceValueMinus6hr = Math.abs(TnoValueMinus6hr-
727                                                   FinalIntensityEstimateValue);
728                        /* System.out.printf("TnoDifferenceValueMinus6hr=%f\n",TnoDifferenceValueMinus6hr); */
729                        /* System.out.printf("PreviousHistoryRule9Value=%d\n",PreviousHistoryRule9Value); */
730                        if(PreviousHistoryRule9Value<2) {
731                            if((TnoDifferenceValueMinus6hr> Rule8AdjArray[Rule8AdjCatValue][2])&& (CurrentTimeMinus6hrTF)) {
732                                FinalIntensityEstimateValue = Math.max(TnoValueMinus6hr-
733                                                      Rule8AdjArray[Rule8AdjCatValue][2],
734                                                      Math.min(TnoValueMinus6hr+
735                                                      Rule8AdjArray[Rule8AdjCatValue][2],
736                                                      FinalIntensityEstimateValue));
737                                Rule8Val = (Rule8AdjCatValue*10)+2;
738                                History.IRCurrentRecord.rule8 = Rule8Val;
739                            }
740                        } else {
741                            if((TnoDifferenceValueMinus6hr> Rule8AdjArray[Rule8AdjCatValue][1])&& (CurrentTimeMinus6hrTF)) {
742                                FinalIntensityEstimateValue = Math.max(TnoValueMinus6hr-
743                                                      Rule8AdjArray[Rule8AdjCatValue][1],
744                                                      Math.min(TnoValueMinus6hr+
745                                                      Rule8AdjArray[Rule8AdjCatValue][1],
746                                                      FinalIntensityEstimateValue));
747                                Rule8Val = (Rule8AdjCatValue*10)+1;
748                                History.IRCurrentRecord.rule8 = Rule8Val;
749                            }
750                        }
751                    }
752                } else {
753                    /* System.out.printf(" GREATER THAN 4.0\n"); */
754                    /* Raw T# >= 4.0 */
755                    TnoDifferenceValueMinus1hr = Math.abs(TnoValueMinus1hr-
756                                                     FinalIntensityEstimateValue);
757                    /* System.out.printf("TnoDifferenceValueMinus1hr=%f\n",TnoDifferenceValueMinus1hr); */
758                    if((TnoDifferenceValueMinus1hr> Rule8AdjArray[Rule8AdjCatValue][9])&& (CurrentTimeMinus1hrTF)&&(ApplyVeldenRuleTF)) {
759                        FinalIntensityEstimateValue = Math.max(TnoValueMinus1hr-
760                                                    Rule8AdjArray[Rule8AdjCatValue][9],
761                                                    Math.min(TnoValueMinus1hr+
762                                                    Rule8AdjArray[Rule8AdjCatValue][9],
763                                                    FinalIntensityEstimateValue));
764                        Rule8Val = (Rule8AdjCatValue*10)+9;
765                        History.IRCurrentRecord.rule8 = Rule8Val;
766                    }
767                    TnoDifferenceValueMinus6hr = Math.abs(TnoValueMinus6hr-FinalIntensityEstimateValue);
768                    TnoDifferenceValueMinus12hr = Math.abs(TnoValueMinus12hr-FinalIntensityEstimateValue);
769                    TnoDifferenceValueMinus18hr = Math.abs(TnoValueMinus18hr-FinalIntensityEstimateValue);
770                    TnoDifferenceValueMinus24hr = Math.abs(TnoValueMinus24hr-FinalIntensityEstimateValue);
771                    /* System.out.printf("Rule8AdjCatValue=%d\n",Rule8AdjCatValue);
772                    /* System.out.printf("current6hrTF=%b TnoDifferenceValueMinus6hr=%f arrayval=%f \n",
773                         CurrentTimeMinus6hrTF,TnoDifferenceValueMinus6hr,Rule8AdjArray[Rule8AdjCatValue][2]); */
774                    /* System.out.printf("current12hrTF=%b TnoDifferenceValueMinus12hr=%f arrayval=%f \n",
775                         CurrentTimeMinus12hrTF,TnoDifferenceValueMinus12hr,Rule8AdjArray[Rule8AdjCatValue][3]); */
776                    /* System.out.printf("current18hrTF=%b TnoDifferenceValueMinus18hr=%f arrayval=%f \n",
777                         CurrentTimeMinus18hrTF,TnoDifferenceValueMinus18hr,Rule8AdjArray[Rule8AdjCatValue][4]); */
778                    /* System.out.printf("current24hrTF=%b TnoDifferenceValueMinus24hr=%f arrayval=%f \n",
779                         CurrentTimeMinus24hrTF,TnoDifferenceValueMinus24hr,Rule8AdjArray[Rule8AdjCatValue][5]); */
780                    
781                    /* NEW Rule 8 MW adjustment*/
782                    if(SpecialPostMWRule8EYEFlag) {
783                        Rule8TESTValue=Rule8AdjArray[Rule8AdjCatValue][6];
784                    } else {
785                        Rule8TESTValue=Rule8AdjArray[Rule8AdjCatValue][2];
786                    }
787                    
788                    if((TnoDifferenceValueMinus6hr> Rule8TESTValue)&& (CurrentTimeMinus6hrTF)) {
789                        /* System.out.printf("6 hr\n"); */
790                        FinalIntensityEstimateValue = Math.max(TnoValueMinus6hr-
791                                                    Rule8TESTValue,
792                                                    Math.min(TnoValueMinus6hr+
793                                                    Rule8TESTValue,
794                                                    FinalIntensityEstimateValue));
795                        if(SpecialPostMWRule8EYEFlag) {
796                            Rule8Val = (Rule8AdjCatValue*10)+6;
797                        } else {
798                            Rule8Val = (Rule8AdjCatValue*10)+2;
799                        }
800                        History.IRCurrentRecord.rule8 = Rule8Val;
801                    } else if((TnoDifferenceValueMinus12hr> Rule8AdjArray[Rule8AdjCatValue][3])&& (CurrentTimeMinus12hrTF)) {
802                        /* System.out.printf("12 hr\n"); */
803                        FinalIntensityEstimateValue = Math.max(TnoValueMinus12hr-
804                                                    Rule8AdjArray[Rule8AdjCatValue][3],
805                                                    Math.min(TnoValueMinus12hr+
806                                                    Rule8AdjArray[Rule8AdjCatValue][3],
807                                                    FinalIntensityEstimateValue));
808                        Rule8Val = (Rule8AdjCatValue*10)+3;
809                        History.IRCurrentRecord.rule8 = Rule8Val;
810                    } else if((TnoDifferenceValueMinus18hr> Rule8AdjArray[Rule8AdjCatValue][4])&& (CurrentTimeMinus18hrTF)) {
811                        /* System.out.printf("18 hr\n"); */
812                        FinalIntensityEstimateValue = Math.max(TnoValueMinus18hr-
813                                                    Rule8AdjArray[Rule8AdjCatValue][4],
814                                                    Math.min(TnoValueMinus18hr+
815                                                    Rule8AdjArray[Rule8AdjCatValue][4],
816                                                    FinalIntensityEstimateValue));
817                        Rule8Val = (Rule8AdjCatValue*10)+4;
818                        History.IRCurrentRecord.rule8 = Rule8Val;
819                    } else if((TnoDifferenceValueMinus24hr> Rule8AdjArray[Rule8AdjCatValue][5])&& (CurrentTimeMinus24hrTF)) {
820                        /* System.out.printf("24 hr\n"); */
821                        FinalIntensityEstimateValue = Math.max(TnoValueMinus24hr-
822                                                    Rule8AdjArray[Rule8AdjCatValue][5],
823                                                    Math.min(TnoValueMinus24hr+
824                                                    Rule8AdjArray[Rule8AdjCatValue][5],
825                                                    FinalIntensityEstimateValue));
826                        Rule8Val = (Rule8AdjCatValue*10)+5;
827                        History.IRCurrentRecord.rule8 = Rule8Val;
828                    } else {
829                        /* System.out.printf("default \n"); */
830                        History.IRCurrentRecord.rule8 = Rule8Val;
831                    }
832                }
833            }
834        }
835        /* System.out.printf("Rule 8 value @ end of intensity calc=%d\n",History.IRCurrentRecord.rule8); */
836        if(MWOFFTF) {
837            /* printf("holding Rule 8 flag to 34\n"); */
838            History.IRCurrentRecord.rule8 = 34;
839        }
840        /*
841        **  NOTE : additional function return points above
842        **  - return Global Initial Strength Value if new history file or
843        **    inserting before first record in existing file
844        */
845        
846        if(Env.DEBUG==100) {
847            System.out.printf("FinalIntensityEstimateValue=%f\n",FinalIntensityEstimateValue);
848        }
849        
850        TnoRawValue = FinalIntensityEstimateValue;
851        double ReturnMWAnalysisFlag = (double)MWAnalysisFlag;
852        
853        return new double[] { TnoRawValue, ReturnMWAnalysisFlag };
854    }
855    
856    /**
857     * Compute time averaged T-Number value using previous and current
858     * intensity estimates.
859     *
860     * <p>Average using a time-weighted averaging scheme.</p>
861     *
862     * @param TimeAvgDurationID Time average duration flag. Use {@code 0} for
863     *                          6 hour and {@code 1} for 3 hour.
864     *
865     * @return Final T# value.
866     */
867    public static double adt_TnoFinal(int TimeAvgDurationID) {
868        /* double TnoFinalValue = 0.0; */
869          
870        double TnoFinalValue = History.IRCurrentRecord.Traw;
871        
872        /* int TimeAvgDurationID = 0; */
873        double OneHourInterval = 1.0/24.0;
874        double BaseTimeAvgValueHrs;
875        double FinalTnoValue;
876        double AverageValue = 0.0;
877        double AverageValueSum = 0.0;
878        double WeightValue = 0.0;
879        double WeightValueSum = 0.0;
880        boolean FoundValuesTF = false;
881        boolean LandCheckTF = false;
882        
883        if(TimeAvgDurationID==1) {
884        BaseTimeAvgValueHrs=3.0;   /* for NHC 3-hour time average value */
885        } else if(TimeAvgDurationID==2) {
886            BaseTimeAvgValueHrs=12.0;  /* for TIE Model time average value */
887        } else {
888            BaseTimeAvgValueHrs=6.0;
889        }
890        
891        int ImageDate = History.IRCurrentRecord.date;
892        int ImageTime = History.IRCurrentRecord.time;
893        double CurrentTime = Functions.calctime(ImageDate,ImageTime);
894        int NumRecsHistory = History.HistoryNumberOfRecords();
895        boolean LandFlagTF = Env.LandFlagTF;
896        
897        /*
898         * compute average with current value with any values
899         * from previous 6 hours
900         */
901        double BeginningTime=CurrentTime-(BaseTimeAvgValueHrs/24.0);
902        
903        int XInc = 0;
904        while(XInc<NumRecsHistory) {
905            int RecDate = History.HistoryFile[XInc].date;
906            int RecTime = History.HistoryFile[XInc].time;
907            double HistoryRecTime = Functions.calctime(RecDate,RecTime);
908            if((HistoryRecTime>=BeginningTime)&&(HistoryRecTime<CurrentTime)) {
909                LandCheckTF = true;
910                if(TimeAvgDurationID<=1) {
911                    AverageValue = History.HistoryFile[XInc].Traw;
912                } else {
913                    if(AverageValue<0.0) {
914                        AverageValue = 0.0;
915                    }
916                }
917                
918                int RecLand = History.HistoryFile[XInc].land;
919                if(((LandFlagTF)&&(RecLand==1))||(AverageValue<1.0)) {
920                    LandCheckTF = false;
921                }
922                if(LandCheckTF) {
923                    double TimeDifference=CurrentTime-HistoryRecTime;
924                    if(TimeAvgDurationID==0) {
925                        /* time weighted average */
926                        WeightValue = (BaseTimeAvgValueHrs-(TimeDifference/OneHourInterval));
927                    } else {
928                        /* straight average */
929                        WeightValue = BaseTimeAvgValueHrs;
930                    }
931                    AverageValueSum = AverageValueSum+(WeightValue*AverageValue);
932                    WeightValueSum = WeightValueSum+WeightValue;
933                    FoundValuesTF = true;
934                }
935            } else {
936               if(FoundValuesTF) {
937                  break;
938               }
939            }
940            XInc++;
941        }
942        /*
943         * compute time-averaged T# value.
944         * if no previous records found, return Raw T#
945         */
946        /* System.out.printf("TRAW=%f\n",History.IRCurrentRecord.Traw); */
947        if(TimeAvgDurationID<=1) {
948            AverageValue = History.IRCurrentRecord.Traw;
949        } else {
950            if(AverageValue<=1.0) {
951                FoundValuesTF = false;
952            }
953        }
954        /* System.out.printf("foundvaluestf=%b averagevalue=%f\n",FoundValuesTF,AverageValue); */
955        if(FoundValuesTF) {
956            AverageValueSum = AverageValueSum+(BaseTimeAvgValueHrs*AverageValue);
957            WeightValueSum = WeightValueSum+BaseTimeAvgValueHrs;
958            /* remove any value remainder past tenths */
959            FinalTnoValue = (double)((int)(((AverageValueSum/WeightValueSum)+0.01)*10.0))/10.0;
960        } else {
961            FinalTnoValue = AverageValue;
962        }
963        /* System.out.printf("finaltnovalue=%f\n",FinalTnoValue); */
964          
965        TnoFinalValue = FinalTnoValue;
966          
967        return TnoFinalValue;
968    }
969    
970    /**
971     * Compute final CI-Number applying various Dvorak Rules, such
972     * as the now famous Rule 9.
973     *
974     * @param HistoryFileName Path to history file.
975     *
976     * @return Array of two doubles. First value represents current intensity,
977     * and the second represents the current strengthening/weakening flag.
978     */
979    // TODO(jon): WHAT IS THIS FAMOUS RULE NUMBER 9!?
980    public static double[] adt_CIno(String HistoryFileName) {
981        int RapidDissIDValue = 0;
982        int CurrentStrengthIDValue;
983        int PreviousHistoryRule9Value = 0;;
984        int Rule9IDValue;
985        double PreviousHistoryFinalTnoValue;
986        double IntensityValue;
987        double TnoMinimumValue = 9.0;            /* T# minimum value */
988        double TnoMaximumValue = 0.0;            /* T# maximum value */
989        double Rule9AdditiveValue = 1.0;
990        double CIadjP;
991        boolean LandOnly12hrTF = true;           /* land only during last 12hrs logical*/
992        boolean LandCheckTF = true;
993        
994        int ImageDate = History.IRCurrentRecord.date;
995        int ImageTime = History.IRCurrentRecord.time;
996        double CurrentTime = Functions.calctime(ImageDate,ImageTime);
997        double Latitude = History.IRCurrentRecord.latitude;
998        double Longitude = History.IRCurrentRecord.longitude;
999        boolean LandFlagTF = Env.LandFlagTF;
1000        double InitStrengthValue = Env.InitRawTValue;
1001        boolean InitStrengthTF = Env.InitStrengthTF;
1002        
1003        int NumRecsHistory = History.HistoryNumberOfRecords();
1004        if(NumRecsHistory==0) {
1005            /* no records in history file */
1006            IntensityValue = History.IRCurrentRecord.Traw;
1007            CurrentStrengthIDValue = 0;
1008            /* this will trip the RULE 9 FLAG for an initial classification of >=6.0 */
1009            if(InitStrengthValue>=6.0) {
1010                CurrentStrengthIDValue = 2;
1011            }
1012            /* Apply Latitude Bias Adjustment to CI value */
1013            //CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,IntensityValue,Latitude,Longitude);
1014            CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,Latitude,Longitude);
1015            History.IRCurrentRecord.CIadjp = CIadjP;
1016            /* return Raw T# for CI# for initial analysis */
1017            return new double[] { IntensityValue, (double)CurrentStrengthIDValue };                                /* EXIT */
1018        }
1019        /* MW Eye Score Adjustment being applied... let CI# = Final T# and return */
1020        int Rule8Current = History.IRCurrentRecord.rule8;
1021        if((Rule8Current>=30)&&(Rule8Current<=33)) {
1022            IntensityValue = History.IRCurrentRecord.Tfinal;
1023            /* Apply Latitude Bias Adjustment to CI value */
1024            //CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,IntensityValue,Latitude,Longitude);
1025            CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,Latitude,Longitude);
1026            History.IRCurrentRecord.CIadjp = CIadjP;
1027            CurrentStrengthIDValue = 0;
1028            return new double[] { IntensityValue, (double)CurrentStrengthIDValue };                                /* EXIT */
1029        }
1030          
1031        /* determine various time threshold values */
1032        double CurrentTimeMinus6Hrs = CurrentTime-0.25;
1033        double CurrentTimeMinus24Hrs = CurrentTime-1.0;
1034          
1035        /* find record just prior to current record */
1036        double PreviousHistoryTnoMaximumValue = 0.0;
1037        double PreviousHistoryTnoMaximum6hrValue = 0.0;
1038        double PreviousHistoryCIValue = 0.0;
1039        double PreviousHistoryRapidDissIDValue = 0;
1040        double PreviousHistoryRapidDissIDMinimumValue = 99;
1041        int XInc = 0;
1042        while(XInc<NumRecsHistory) {
1043            int RecDate = History.HistoryFile[XInc].date;
1044            int RecTime = History.HistoryFile[XInc].time;
1045            double HistoryRecTime = Functions.calctime(RecDate,RecTime);
1046            if(HistoryRecTime>=CurrentTime) {
1047                break;
1048            }
1049            int RecLand = History.HistoryFile[XInc].land;
1050            double Traw = History.HistoryFile[XInc].Traw;
1051            LandCheckTF = true;
1052            if(((LandFlagTF)&&(RecLand==1))||(Traw<1.0)) {
1053                LandCheckTF = false;
1054            }
1055            if(LandCheckTF) {
1056                PreviousHistoryFinalTnoValue = History.HistoryFile[XInc].Tfinal;
1057                PreviousHistoryCIValue = History.HistoryFile[XInc].CI;
1058                PreviousHistoryRule9Value = History.HistoryFile[XInc].rule9;
1059                PreviousHistoryRapidDissIDValue = History.HistoryFile[XInc].rapiddiss;
1060                /* check Rule 9 */
1061                if(HistoryRecTime>=CurrentTimeMinus6Hrs) {
1062                    /* find largest finalT# in last 6 hours prior to current record */
1063                    if(PreviousHistoryFinalTnoValue>PreviousHistoryTnoMaximumValue) {
1064                        PreviousHistoryTnoMaximumValue = PreviousHistoryFinalTnoValue;
1065                    }
1066                }
1067                if(HistoryRecTime>=CurrentTimeMinus6Hrs) {
1068                    /* if storm is over land for SIX hours, turn off Rule 9
1069                       (changed from 12 hours) */
1070                    LandOnly12hrTF = false;
1071                    
1072                    /* rapid dissapation check */
1073                    if(PreviousHistoryRapidDissIDValue<PreviousHistoryRapidDissIDMinimumValue) {
1074                        PreviousHistoryRapidDissIDMinimumValue = PreviousHistoryRapidDissIDValue;
1075                    }
1076                    if(PreviousHistoryFinalTnoValue>PreviousHistoryTnoMaximum6hrValue) {
1077                        PreviousHistoryTnoMaximum6hrValue = PreviousHistoryFinalTnoValue;
1078                    }
1079                }
1080                if(HistoryRecTime>=CurrentTimeMinus24Hrs) {
1081                    /* find min and max finalT# in last 24 hours prior to current record */
1082                    if(PreviousHistoryFinalTnoValue<TnoMinimumValue) {
1083                        TnoMinimumValue = PreviousHistoryFinalTnoValue;
1084                    }
1085                    if(PreviousHistoryFinalTnoValue>TnoMaximumValue) {
1086                        TnoMaximumValue = PreviousHistoryFinalTnoValue;
1087                    }
1088                }
1089            }
1090            XInc++;
1091        }
1092        
1093        IntensityValue = History.IRCurrentRecord.Tfinal;
1094        
1095        if(XInc==0) {
1096            /* current record is before first record in history file */
1097            CurrentStrengthIDValue=0;
1098            /* Apply Latitude Bias Adjustment to CI value */
1099            //CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,IntensityValue,Latitude,Longitude);
1100            CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,Latitude,Longitude);
1101            History.IRCurrentRecord.CIadjp = CIadjP;
1102            /* return Final T# for CI# for initial analysis */
1103            return new double[] { IntensityValue, (double)CurrentStrengthIDValue };                                /* EXIT */
1104        }
1105        
1106        Rule9IDValue = PreviousHistoryRule9Value;
1107        int[] ReturnValues3 = Functions.adt_oceanbasin(Latitude,Longitude);
1108        int BasinID_Local = ReturnValues3[0];
1109        
1110        /* rapid dissipation determination */
1111        double Slope6hrValue = Functions.adt_slopecal(6.0,2);
1112        if(PreviousHistoryRapidDissIDValue<=1) {
1113            RapidDissIDValue = 0;
1114            /* if(Slope6hrValue>=2.0) { */
1115            /* relax rapid weakening criteria for the East Pac */
1116            if(((BasinID_Local!=2)&&(Slope6hrValue>=2.0))|| ((BasinID_Local==2)&&(Slope6hrValue>=1.5))) {
1117                /* 2.0/24 hours or 1.5/24 hours for East Pac */
1118                RapidDissIDValue = 1;
1119            }
1120            if((PreviousHistoryRapidDissIDMinimumValue==1)&&(RapidDissIDValue==1)) {
1121                Rule9AdditiveValue = 0.5;
1122                RapidDissIDValue = 2;
1123            }
1124        } else {
1125            Rule9AdditiveValue = 0.5;
1126            RapidDissIDValue = 2;
1127            /* if(Slope6hrValue<1.5) { */
1128            if(((BasinID_Local!=2)&&(Slope6hrValue<1.5))|| ((BasinID_Local==2)&&(Slope6hrValue<1.0))) {
1129                /* 1.5/24 hours or 1.0/24 hours for East Pac */
1130                RapidDissIDValue = 3;
1131            }
1132            if((PreviousHistoryRapidDissIDMinimumValue==3)&&(RapidDissIDValue==3)) {
1133                Rule9AdditiveValue = 1.0;
1134                RapidDissIDValue = 0;
1135            }
1136        }
1137        
1138        /*
1139         * strength flags : 0 - strengthening, but not significant
1140         *                  1 - applying Max's 12 hour max Tno. rule
1141         */
1142        /* determine CI# */
1143        double CurrentTnoValue = IntensityValue;
1144        double CurrentTnoPlusRule9Value = IntensityValue+Rule9AdditiveValue;
1145        /*
1146         * We have once again returned to using the 6 hour Max T# value
1147         * for all basins for the Rule 9 check
1148         */
1149        double CIValue = Math.min(CurrentTnoPlusRule9Value,
1150                      Math.max(PreviousHistoryTnoMaximumValue,CurrentTnoValue));
1151                      
1152        /* will utilize Max's Rule all of the time */
1153        if(CIValue>CurrentTnoValue) {
1154            Rule9IDValue = 1;
1155        }
1156        if((PreviousHistoryRule9Value==1)&&(PreviousHistoryCIValue<=CurrentTnoValue)) {
1157            Rule9IDValue = 0;
1158        }
1159        
1160        /*
1161         * check for land interaction
1162         * if undergoing interactation with land "turn off" Rule 9
1163         * application and return CI value to Adjusted Raw Tno value for >= 3 hours (was 12 hours)
1164         */
1165        if(LandOnly12hrTF) {
1166            /*
1167             * if land flag is TRUE,
1168             * turn off Rule 9 and let CI value be equal to the
1169             * current Adjusted Raw T# value, and return (was Final T#)
1170             * current intensity flag to "insignificant value" until
1171             * another significant strengtheing cycle occurs
1172             */
1173            Rule9IDValue = 0;
1174            CIValue = History.IRCurrentRecord.Traw;
1175            RapidDissIDValue = 0;
1176        }
1177        /* Apply Latitude Bias Adjustment to CI value */
1178        //CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,CIValue,Latitude,Longitude);
1179        CIadjP = adt_latbias(InitStrengthTF,LandFlagTF,HistoryFileName,Latitude,Longitude);
1180        /* System.out.printf("CIno: ciadjp=%f\n",CIadjP); */
1181        History.IRCurrentRecord.CIadjp = CIadjP;
1182        History.IRCurrentRecord.rapiddiss = RapidDissIDValue;
1183        
1184        CurrentStrengthIDValue = Rule9IDValue;
1185        
1186        return new double[] { CIValue, (double)CurrentStrengthIDValue };
1187    }
1188    
1189    /**
1190     * Apply Latitude Bias Adjustment to CI value.
1191     *
1192     * @param InitStrengthTF
1193     * @param LandFlagTF Flag that represents land status.
1194     * @param HistoryFileName Path to history file.
1195     * @param InputLatitude Current latitude of storm.
1196     * @param InputLongitude Current longitude of storm.
1197     *
1198     * @return Adjusted MSLP value.
1199     */
1200    public static double adt_latbias(boolean InitStrengthTF,
1201                                     boolean LandFlagTF,
1202                                     String HistoryFileName,
1203                                     double InputLatitude,
1204                                     double InputLongitude)
1205    {
1206        double ReturnCIPressureAdjValue = 0.0;
1207        boolean UseCKZTF = Env.UseCKZTF;
1208        if(!UseCKZTF) {
1209            double[] RetVals = adt_scenesearch(HistoryFileName,InitStrengthTF,LandFlagTF);
1210            int LatBiasAdjFlagID = (int)RetVals[0];
1211            double AdjustmentMultFactor = RetVals[1];
1212            History.IRCurrentRecord.LBflag = LatBiasAdjFlagID;
1213            /* System.out.printf("latbiasadjflagid=%d\n",LatBiasAdjFlagID); */
1214            if(LatBiasAdjFlagID>=2) {
1215                /* EIR scene */
1216                if((InputLatitude>=0.0)&&((InputLongitude>=-100.0)&& (InputLongitude<=-40.0))) {
1217                    /* do not make adjustment in N Indian Ocean */
1218                    ReturnCIPressureAdjValue = 0.0;
1219                } else {
1220                    /* apply bias adjustment to pressure */
1221                    ReturnCIPressureAdjValue = AdjustmentMultFactor*
1222                                             (7.325-(0.302*Math.abs(InputLatitude)));
1223                }
1224            }
1225        }
1226        return ReturnCIPressureAdjValue;
1227    }
1228    
1229    /**
1230     * Search for valid scene range for Latitude Bias Adjustment application.
1231     * Inputs  : None
1232     * Outputs : AdjustmentMultFactor_Return - multiplicative value for merging
1233     * Return  : 0 - first record in new history file
1234     *           1 - non Enhanced Infrared scene or intermediate/merging application
1235     *           2 - entering/leaving valid adjustment time period.  Also used for
1236     *               non-history file intensity analysis (full adjustment)
1237     *
1238     * @param HistoryFileName Path to history file.
1239     * @param InitStrengthTF
1240     * @param LandFlagTF Over land?
1241     *
1242     * @return Array of two doubles. The first value represents latitude bias
1243     * adjustment, while the second value represents the adjustment's
1244     * multiplicative factor.
1245     */
1246    public static double[] adt_scenesearch(String HistoryFileName,
1247                                           boolean InitStrengthTF,
1248                                           boolean LandFlagTF)
1249    {
1250        int LatBiasAdjFlagID = -1;
1251        double AdjustmentMultFactor = 0.0;
1252        
1253        int NumRecsHistory = History.HistoryNumberOfRecords();
1254        if(((NumRecsHistory==0)&&(InitStrengthTF))&&(HistoryFileName!=null)) {
1255           return new double[] { 0.0, -999.9 };
1256        }
1257        if(HistoryFileName==null) {
1258           return new double[] { 2.0, 1.0 };
1259        }
1260        
1261        int HistoryRecLatBiasAdjFlagIDValue = 0;
1262        
1263        int CloudScene = History.IRCurrentRecord.cloudscene;
1264        /* System.out.printf("cloudscene=%d\n",CloudScene); */
1265        if((CloudScene>=2)&&(CloudScene<6)) LatBiasAdjFlagID = 0;
1266              
1267        int ImageDate = History.IRCurrentRecord.date;
1268        int ImageTime = History.IRCurrentRecord.time;
1269        double CurrentTime = Functions.calctime(ImageDate,ImageTime);
1270        double CurrentTimeMinus6hr = CurrentTime - 0.26;
1271        double MergePeriodFirstTime = CurrentTime;
1272        
1273        int RecDate,RecTime,RecLand;
1274        double HistoryRecTime;
1275        double RecTnoRaw;
1276        boolean LandCheckTF=true;
1277        boolean EIRSceneTypeTF=true;
1278        boolean FoundMergePeriodFirstRecordTF = false;
1279        double FirstHistoryRecTime = -99999.0;
1280        
1281        int XInc=0;
1282        while(XInc<NumRecsHistory) {
1283            RecDate = History.HistoryFile[XInc].date;
1284            RecTime = History.HistoryFile[XInc].time;
1285            HistoryRecTime = Functions.calctime(RecDate,RecTime);
1286            RecLand = History.HistoryFile[XInc].land;
1287            RecTnoRaw = History.HistoryFile[XInc].Traw;
1288            if(((LandFlagTF)&&(RecLand==1))||(RecTnoRaw<1.0)) {
1289                LandCheckTF = false;
1290            }
1291            if((HistoryRecTime<CurrentTime)&&(LandCheckTF)) {
1292                HistoryRecLatBiasAdjFlagIDValue = History.HistoryFile[XInc].LBflag;
1293                /* System.out.printf("Historyrectime=%f  Currtimem6=%f  eirscenetypetf=%b\n",HistoryRecTime,CurrentTimeMinus6hr,EIRSceneTypeTF); */
1294                if((HistoryRecTime>=CurrentTimeMinus6hr)&&(EIRSceneTypeTF)) {
1295                    if(FirstHistoryRecTime<0.0) {
1296                        FirstHistoryRecTime = HistoryRecTime;
1297                    }
1298                    /* System.out.printf("HistoryRecLatBiasAdjFlagIDValue=%d\n",HistoryRecLatBiasAdjFlagIDValue); */
1299                    if(HistoryRecLatBiasAdjFlagIDValue==0) {
1300                        EIRSceneTypeTF = false;
1301                    }
1302                    if(HistoryRecLatBiasAdjFlagIDValue==2) {
1303                        if(!FoundMergePeriodFirstRecordTF) {
1304                            MergePeriodFirstTime = HistoryRecTime;
1305                            FoundMergePeriodFirstRecordTF = true;
1306                        }
1307                    }
1308                }
1309            }
1310            XInc++;
1311        }
1312        
1313        /* System.out.printf("scenesearch: FirstHistoryRecTime=%f\n",FirstHistoryRecTime); */
1314        if(FirstHistoryRecTime<0.0) {
1315            /* there is a six hour gap in the data for some reason...
1316               I will use the last value available */
1317            LatBiasAdjFlagID=HistoryRecLatBiasAdjFlagIDValue;
1318            if(HistoryRecLatBiasAdjFlagIDValue>=1) {
1319                LatBiasAdjFlagID = 2;
1320            }
1321            AdjustmentMultFactor = 1.0;
1322        } else {
1323            /* System.out.printf("scenesearch: eirscenetypetf=%b",EIRSceneTypeTF); */
1324            if(EIRSceneTypeTF) {
1325                /* entering or in valid lat bias adjustment period */
1326                LatBiasAdjFlagID = 2;
1327                /* return value from 0 to 1 */
1328                AdjustmentMultFactor = (CurrentTime-MergePeriodFirstTime)/
1329                                       (CurrentTime-FirstHistoryRecTime);
1330            } else {
1331                /* LatBiasAdjFlagID = LatBiasAdjFlagID; */
1332                AdjustmentMultFactor = -999.0;
1333            }
1334        }
1335        return new double[] { (double)LatBiasAdjFlagID, AdjustmentMultFactor };
1336    }
1337}