using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using DotSpatial.Data;
using DotSpatial.Projections;
using System.Collections.Concurrent;

namespace SMAT_CE
{
    class SSIACommonClass
    {
        public static DateTime _beginTime;
        public static DateTime _endTime;

        public static string _resultFilePath = "";

        #region SSIA Annual PM
        public static bool AnnualPMAnalysisSSIA(BaseScenario baseScenario, SMAT_CE mats)
        {
            if (!(baseScenario.configuration is SSIAAnnualPMAnalysisConfiguration))
            {
                return false;
            }
            try
            {
                _beginTime = DateTime.Now;
                SSIAAnnualPMAnalysisConfiguration annualPMSSIAAnalysisConfiguration = baseScenario.configuration as SSIAAnnualPMAnalysisConfiguration;
                if (!CommonClass.IsBatch)
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName;
                }
                else
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName;
                }
                if (!Directory.Exists(_resultFilePath))
                    System.IO.Directory.CreateDirectory(_resultFilePath);
                string isOK = "";

                #region read model data
                Dictionary<string, SSIAAnnualPMDataOutput> dicDataPMSSIAGrid = new Dictionary<string, SSIAAnnualPMDataOutput>();
                Dictionary<string, SSIAAnnualPMDataOutput> dicDataPMSSIADispersion = new Dictionary<string, SSIAAnnualPMDataOutput>();

                CommonClass.CurrentBaseScenario.dicLatLongLambert = new Dictionary<string, string>();
                CommonClass.CurrentBaseScenario.dicLambertLatLong = new Dictionary<string, string>();
                //string baseModelYear = "", futureModelYear = "";
                #region read cmaq
                if (!annualPMSSIAAnalysisConfiguration.analysisOptionA.useDispersionOnly)
                {
                    CommonClass.CurrentLog = "Read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.baselineModelDataFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                    if (annualPMSSIAAnalysisConfiguration.modelInputA.QuarterlyModelDataInput || annualPMSSIAAnalysisConfiguration.modelInputA.DailyModelDataInput)
                    {
                        isOK = GetModelData(annualPMSSIAAnalysisConfiguration, ref dicDataPMSSIAGrid);//, ref baseModelYear, ref futureModelYear);
                        switch (isOK)//error message when loading file
                        {
                            case "wrongBaseline":
                                CommonClass.CurrentLog = "Fail to read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.baselineModelDataFile) + "\".";
                                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                                return false;
                            case "wrongFuture":
                                CommonClass.CurrentLog = "Fail to read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.alternativeScenarioFile) + "\".";
                                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                                return false;
                            case "unknow":
                                CommonClass.CurrentLog = "Fail to read model data.";
                                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                                return false;
                        }
                    }
                    else if (annualPMSSIAAnalysisConfiguration.modelInputA.InputFromCMAQ)
                    {
                        CommonClass.CurrentLog = "Read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.dispersionFile) + "\".";
                        CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                    }

                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s.";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    //change project - write in dictionary (lat,long to lambert) - for draw map
                    double[] dConvertArray = null;
                    List<double> lstConvertArray = new List<double>();
                    List<string> lstKey = dicDataPMSSIAGrid.Keys.ToList();
                    for (int iLstKey = 0; iLstKey < dicDataPMSSIAGrid.Keys.Count; iLstKey++)
                    {
                        lstConvertArray.Add(dicDataPMSSIAGrid[lstKey[iLstKey]].longitude);
                        lstConvertArray.Add(dicDataPMSSIAGrid[lstKey[iLstKey]].lat);
                    }
                    dConvertArray = lstConvertArray.ToArray();
                    DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArray, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984, DotSpatial.Projections.ProjectionInfo.FromProj4String(CommonClass.projUSACMAQ), 0, dConvertArray.Length / 2);
                    for (int iLstKey = 0; iLstKey < dicDataPMSSIAGrid.Keys.Count; iLstKey++)
                    {
                        dicDataPMSSIAGrid[lstKey[iLstKey]].longitudeLamber = dConvertArray[2 * iLstKey] / 100.0;
                        dicDataPMSSIAGrid[lstKey[iLstKey]].latitudeLamber = dConvertArray[2 * iLstKey + 1] / 100.0;
                        string data = dConvertArray[2 * iLstKey] + "," + dConvertArray[2 * iLstKey + 1];
                        //if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly)
                        if (!CommonClass.CurrentBaseScenario.dicLatLongLambert.ContainsKey(dicDataPMSSIAGrid[lstKey[iLstKey]].lat + "," + dicDataPMSSIAGrid[lstKey[iLstKey]].longitude))
                        {
                            CommonClass.CurrentBaseScenario.dicLatLongLambert.Add(dicDataPMSSIAGrid[lstKey[iLstKey]].lat + "," + dicDataPMSSIAGrid[lstKey[iLstKey]].longitude, data);
                            if (!CommonClass.CurrentBaseScenario.dicLambertLatLong.ContainsKey(data))
                            {
                                CommonClass.CurrentBaseScenario.dicLambertLatLong.Add(data, dicDataPMSSIAGrid[lstKey[iLstKey]].id + "," + dicDataPMSSIAGrid[lstKey[iLstKey]].lat + "," + dicDataPMSSIAGrid[lstKey[iLstKey]].longitude);
                            }
                        }
                    }
                }
                #endregion

                #region read aermod
                if (!annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly)
                {
                    int idrestart = 0;
                    if (dicDataPMSSIAGrid.Count > 0)
                    {
                        foreach (string id in dicDataPMSSIAGrid.Keys)
                        {
                            idrestart = Math.Max(idrestart, Convert.ToInt32(id));
                        }
                    }
                    _beginTime = DateTime.Now;
                    CommonClass.CurrentLog = "Read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.dispersionFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                    isOK = GetDispersionModelData(annualPMSSIAAnalysisConfiguration, ref dicDataPMSSIADispersion, idrestart);
                    if (isOK == "wrong")
                    {
                        CommonClass.CurrentLog = "Fail to read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.dispersionFile) + "\".";
                        CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                        return false;
                    }

                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s.";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                    //change proj to wgs1984 from utm
                    double[] dConvertArray = null;
                    List<double> lstConvertArray = new List<double>();
                    List<string> lstKey = dicDataPMSSIADispersion.Keys.ToList();
                    for (int iLstKey = 0; iLstKey < dicDataPMSSIADispersion.Keys.Count; iLstKey++)
                    {
                        lstConvertArray.Add(dicDataPMSSIADispersion[lstKey[iLstKey]].longitudeUTM * 100.0 + 738547);
                        lstConvertArray.Add(dicDataPMSSIADispersion[lstKey[iLstKey]].latitudeUTM * 100.0 + 3724842);
                    }
                    dConvertArray = lstConvertArray.ToArray();
                    DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArray, null, DotSpatial.Projections.ProjectionInfo.FromProj4String(CommonClass.projUSAAERMOD), DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984, 0, dConvertArray.Length / 2);

                    if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useDispersionOnly)
                    {
                        CommonClass.CurrentBaseScenario.dicLatLongLambert = new Dictionary<string, string>();
                        CommonClass.CurrentBaseScenario.dicLambertLatLong = new Dictionary<string, string>();
                        for (int iLstKey = 0; iLstKey < dicDataPMSSIADispersion.Keys.Count; iLstKey++)
                        {
                            dicDataPMSSIADispersion[lstKey[iLstKey]].longitude = Math.Round(dConvertArray[2 * iLstKey], 6);
                            dicDataPMSSIADispersion[lstKey[iLstKey]].lat = Math.Round(dConvertArray[2 * iLstKey + 1], 6);
                            string data = (dicDataPMSSIADispersion[lstKey[iLstKey]].longitudeUTM * 100.0 + 738547) + "," + (dicDataPMSSIADispersion[lstKey[iLstKey]].latitudeUTM * 100.0 + 3724842);
                            if (!CommonClass.CurrentBaseScenario.dicLatLongLambert.ContainsKey("utm," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude))
                            {
                                CommonClass.CurrentBaseScenario.dicLatLongLambert.Add("utm," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude, data);
                                if (!CommonClass.CurrentBaseScenario.dicLambertLatLong.ContainsKey(data))
                                {
                                    CommonClass.CurrentBaseScenario.dicLambertLatLong.Add(data, dicDataPMSSIADispersion[lstKey[iLstKey]].id + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude);
                                }
                            }
                        }
                    }
                    else
                    //if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion)
                    {
                        for (int iLstKey = 0; iLstKey < dicDataPMSSIADispersion.Keys.Count; iLstKey++)
                        {
                            dicDataPMSSIADispersion[lstKey[iLstKey]].longitude = Math.Round(dConvertArray[2 * iLstKey], 6);
                            dicDataPMSSIADispersion[lstKey[iLstKey]].lat = Math.Round(dConvertArray[2 * iLstKey + 1], 6);
                            string data = (dicDataPMSSIADispersion[lstKey[iLstKey]].longitudeUTM * 100.0 + 738547) + "," + (dicDataPMSSIADispersion[lstKey[iLstKey]].latitudeUTM * 100.0 + 3724842);
                            if (!CommonClass.CurrentBaseScenario.dicLatLongLambert.ContainsKey("utm," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude))
                            {
                                CommonClass.CurrentBaseScenario.dicLatLongLambert.Add("utm," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude, data);
                                if (!CommonClass.CurrentBaseScenario.dicLambertLatLong.ContainsKey(data))
                                {
                                    CommonClass.CurrentBaseScenario.dicLambertLatLong.Add(data, dicDataPMSSIADispersion[lstKey[iLstKey]].id + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude);
                                }
                            }
                        }

                        //Dictionary<string, double[]> dicWGS1989toLCC = new Dictionary<string, double[]>();
                        //change proj to lcc from wgs1984
                        DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArray, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984, DotSpatial.Projections.ProjectionInfo.FromProj4String(CommonClass.projUSACMAQ), 0, dConvertArray.Length / 2);
                        for (int iLstKey = 0; iLstKey < dicDataPMSSIADispersion.Keys.Count; iLstKey++)
                        {
                            dicDataPMSSIADispersion[lstKey[iLstKey]].longitudeLamber = dConvertArray[2 * iLstKey] / 100.0;
                            dicDataPMSSIADispersion[lstKey[iLstKey]].latitudeLamber = dConvertArray[2 * iLstKey + 1] / 100.0;
                            string data = dConvertArray[2 * iLstKey] + "," + dConvertArray[2 * iLstKey + 1];
                            if (!CommonClass.CurrentBaseScenario.dicLatLongLambert.ContainsKey(dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude))
                            {
                                CommonClass.CurrentBaseScenario.dicLatLongLambert.Add(dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude, "d," + data);
                                if (!CommonClass.CurrentBaseScenario.dicLambertLatLong.ContainsKey(data))
                                {
                                    CommonClass.CurrentBaseScenario.dicLambertLatLong.Add(data, dicDataPMSSIADispersion[lstKey[iLstKey]].id + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].lat + "," + dicDataPMSSIADispersion[lstKey[iLstKey]].longitude);
                                }
                            }
                        }

                        //for (int iLstKey = 0; iLstKey < dicDataPMSSIATmp.Keys.Count; iLstKey++)
                        //{
                        //    if (!dicWGS1989toLCC.ContainsKey(lstKey[iLstKey]))
                        //        dicWGS1989toLCC.Add(lstKey[iLstKey], new double[2]);
                        //    dicWGS1989toLCC[lstKey[iLstKey]][0] = dConvertArray[2 * iLstKey] / 100.0;//long
                        //    dicWGS1989toLCC[lstKey[iLstKey]][1] = dConvertArray[2 * iLstKey + 1] / 100.0;//lat
                        //}

                        //aremod point in cmaq grid
                        double dLon = 0, dLat = 0;
                        int iFirst = Convert.ToInt32(dicDataPMSSIAGrid.First().Key);
                        if (dicDataPMSSIAGrid.ContainsKey((((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()))
                        {
                            dLon = Math.Abs(dicDataPMSSIAGrid[(((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()].longitudeLamber -
                                    dicDataPMSSIAGrid.First().Value.longitudeLamber);
                            dLon = dLon / 2;
                            dLat = Math.Abs(dicDataPMSSIAGrid[(((iFirst / 1000)) * 1000 + iFirst % 1000 + 1).ToString()].latitudeLamber -
                                dicDataPMSSIAGrid.First().Value.latitudeLamber);
                            dLat = dLat / 2;
                        }
                        foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataPMSSIADispersion)
                        {
                            try
                            {
                                //if (k.Value.id == "1001")//test
                                //{ }
                                double lat = k.Value.latitudeLamber;//dicWGS1989toLCC[k.Key][1];
                                double longtitude = k.Value.longitudeLamber;//dicWGS1989toLCC[k.Key][0];
                                var query = dicDataPMSSIAGrid.Where(p => Math.Abs(p.Value.longitudeLamber - longtitude) < dLon && Math.Abs(p.Value.latitudeLamber - lat) < dLat).ToList();
                                string sModelIDTemp = "";
                                if (query.Count() > 0)
                                {
                                    //if (query.Count() > 1)//test
                                    //{ }

                                    DotSpatial.Topology.Coordinate coor = new DotSpatial.Topology.Coordinate(longtitude, lat);
                                    sModelIDTemp = query.OrderBy(p => Math.Pow(p.Value.longitude - longtitude, 2) + Math.Pow(p.Value.latitudeLamber - lat, 2)).First().Key;
                                    k.Value.dicDeltaModel["0"].pm25 = dicDataPMSSIAGrid[sModelIDTemp].dicDeltaModel["0"].pm25sec + k.Value.dicDeltaModel["0"].pm25prim;
                                    k.Value.dicDeltaModel["0"].pm25sec = dicDataPMSSIAGrid[sModelIDTemp].dicDeltaModel["0"].pm25sec;
                                    k.Value.dicBaselineModel = new Dictionary<string, ModelDataSpecies>();
                                    foreach (KeyValuePair<string, ModelDataSpecies> baseline in dicDataPMSSIAGrid[sModelIDTemp].dicBaselineModel)
                                    {
                                        k.Value.dicBaselineModel.Add(baseline.Key, baseline.Value);//for quarterly evna -when option is combine- can calculate once to generate Combine and Grid model data
                                    }
                                    //k.Value.dicBaselineModel.Add("0", new ModelDataSpecies());
                                    //k.Value.dicBaselineModel["0"].pm25 = dicDataPMSSIAGrid[sModelIDTemp].dicBaselineModel["0"].pm25;
                                    //k.Value.dicBaselineModel["0"].pm25sec = dicDataPMSSIAGrid[sModelIDTemp].dicBaselineModel["0"].pm25sec;
                                    k.Value.dicAlternativeModel = new Dictionary<string, ModelDataSpecies>();
                                    k.Value.dicAlternativeModel.Add("0", new ModelDataSpecies());
                                    k.Value.dicAlternativeModel["0"].pm25 = k.Value.dicBaselineModel["0"].pm25 + k.Value.dicDeltaModel["0"].pm25;
                                    k.Value.dicAlternativeModel["0"].pm25sec = dicDataPMSSIAGrid[sModelIDTemp].dicAlternativeModel["0"].pm25sec;
                                    //test
                                    //k.Value.AlternativeModel = new ModelDataSpecies();
                                    //k.Value.AlternativeModel.pm25 = dicDataPMSSIA[sModelIDTemp].AlternativeModel.pm25;
                                    //k.Value.DeltaModel.pm25 += dicDataPMSSIA[sModelIDTemp].AlternativeModel.pm25;
                                }
                            }
                            catch
                            { }
                        }
                    }
                    //dicDataPMSSIA = dicDataPMSSIATmp;
                    //foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataPMSSIADispersion)
                    //{
                    //    dicDataPMSSIAGrid.Add(k.Key, k.Value);
                    //}
                }
                #endregion
                #endregion

                #region Calculate cell center distance from source
                Dictionary<string, double[]> dicCells = new Dictionary<string, double[]>();
                if (!annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly)
                {
                    foreach (var item in dicDataPMSSIADispersion)
                    {
                        double[] v = new double[3] { item.Value.lat, item.Value.longitude, 0 };
                        dicCells.Add(item.Value.id, v);
                    }
                }
                if (!annualPMSSIAAnalysisConfiguration.analysisOptionA.useDispersionOnly)
                {
                    foreach (var item in dicDataPMSSIAGrid)
                    {
                        double[] v = new double[3] { item.Value.lat, item.Value.longitude, 0 };
                        dicCells.Add(item.Value.id, v);
                    }
                }


                #region Read Source File
                Dictionary<string, double[]> dicSource = new Dictionary<string, double[]>();
                FileStream fs = new FileStream(annualPMSSIAAnalysisConfiguration.modelInputA.SourceCoordinateFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                using (StreamReader csv = new StreamReader(fs, System.Text.Encoding.UTF8))
                {
                    string strLine = csv.ReadLine();//header
                    strLine = csv.ReadLine();
                    string[] strLineArray;
                    while (strLine != null)
                    {
                        strLineArray = strLine.Split(new char[] { ',' });
                        double[] v = new double[2] { Convert.ToDouble(strLineArray[1]), Convert.ToDouble(strLineArray[2]) };
                        dicSource.Add(strLineArray[0], v);
                        strLine = csv.ReadLine();
                    }
                    csv.Dispose(); fs.Dispose();
                    GC.Collect();
                }
                #endregion

                #region Output Source Location file
                string filename = annualPMSSIAAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Source Location.csv";
                BaseOutput baseOutput = new BaseOutput();
                File.Copy(annualPMSSIAAnalysisConfiguration.modelInputA.SourceCoordinateFile, _resultFilePath + "\\" + filename, true);
                baseOutput.outputName = filename.Replace(".csv", "");
                baseOutput.outputType = "Source Location";
                baseOutput.outputFilePath = _resultFilePath + "\\" + filename;
                if (File.Exists(baseOutput.outputFilePath))
                {
                    FileInfo fileInfo = new FileInfo(baseOutput.outputFilePath);
                    baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                }
                else
                {
                    baseOutput.outputSize = 0;
                }
                baseScenario.lstOutput.Add(baseOutput);

                CalculateDistance(ref dicCells, dicSource);

                #endregion
                #endregion

                //_endTime = DateTime.Now;
                //CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                //CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish reading model data: " + CommonClass.TotalTime + " s.");
                //CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s.";
                //_beginTime = DateTime.Now;
                if (!annualPMSSIAAnalysisConfiguration.analysisOptionA.useModelFRMData)
                {
                    string type = "";
                    if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion)
                        type = "combine,grid,dispersion,quarter";
                    if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly)
                        type = "grid";
                    if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useDispersionOnly)
                        type = "dispersion";
                    SaveSSIAAnnualPMData(baseScenario, dicDataPMSSIAGrid, dicDataPMSSIADispersion, false, false, type, dicCells);
                    return true;
                }

                _beginTime = DateTime.Now;
                CommonClass.CurrentLog = "Read monitor data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.monitorInputA.officialMonitorDataFile) + "\".";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitorsTmp = new Dictionary<string, SSIAAnnualPMOfficial>();
                //----------read official PM monitors file------------
                isOK = GetOfficialPmMonitors(annualPMSSIAAnalysisConfiguration, ref dicOfficialPMMonitorsTmp);
                if (dicOfficialPMMonitorsTmp.Count <= 0 || isOK == "unknow")//error message when loading file
                {
                    CommonClass.CurrentLog = "Fail to read monitor data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.monitorInputA.officialMonitorDataFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    return false;
                }
                //else
                //{
                //    if (isOK == "errorRow")
                //    {
                //        CommonClass.CurrentLog = "There are errors in the monitor file of " + annualPMSSIAAnalysisConfiguration.monitorInputA.officialMonitorDataFile + ". The error rows were removed.";
                //        CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                //    }
                //}

                //----------get DV periods-----------
                List<string> dicDesignValluePeriods = new List<string>();
                int startYear = Convert.ToInt32(annualPMSSIAAnalysisConfiguration.monitorInputA.monitorDataStartYear);
                int endYear = Convert.ToInt32(annualPMSSIAAnalysisConfiguration.monitorInputA.monitorDataEndYear);
                if (endYear < startYear + 2)
                {
                    dicDesignValluePeriods.Add(startYear.ToString() + "-" + endYear.ToString());
                }
                else
                {
                    for (int i = 0; i < endYear - startYear - 1; i++)
                    {
                        dicDesignValluePeriods.Add((startYear + i).ToString() + "-" + (startYear + 2 + i).ToString());
                    }
                }
                #region get baseline FRM data - official DV
                Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitors = new Dictionary<string, SSIAAnnualPMOfficial>();
                List<string> lstYear = new List<string>();
                PMCalculationOfficialChoice(annualPMSSIAAnalysisConfiguration, dicOfficialPMMonitorsTmp, dicDesignValluePeriods, ref dicOfficialPMMonitors);
                #endregion
                dicOfficialPMMonitorsTmp.Clear();
                GC.Collect();

                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentLog = "Finish reading monitor data: " + CommonClass.TotalTime + " s.";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                //_endTime = DateTime.Now;
                //CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                //CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish reading monitor data: " + CommonClass.TotalTime + " s.");
                //CommonClass.CurrentLog = "Finish reading monitor data: " + CommonClass.TotalTime + " s.";
                #region point and spatial field
                _beginTime = DateTime.Now;

                if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion)
                {
                    #region point
                    double[] dConvertArraySpatial = null;
                    List<double> lstConvertArraySpatial = new List<double>();
                    List<string> lstKeySpatial = dicOfficialPMMonitors.Keys.ToList();
                    for (int iLstKey = 0; iLstKey < dicOfficialPMMonitors.Keys.Count; iLstKey++)
                    {
                        lstConvertArraySpatial.Add(dicOfficialPMMonitors[lstKeySpatial[iLstKey]].longitude);
                        lstConvertArraySpatial.Add(dicOfficialPMMonitors[lstKeySpatial[iLstKey]].latitude);
                    }
                    dConvertArraySpatial = lstConvertArraySpatial.ToArray();
                    DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArraySpatial, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984,
       ProjectionInfo.FromProj4String(CommonClass.projUSACMAQ), 0, dConvertArraySpatial.Length / 2);
                    for (int iLstKey = 0; iLstKey < dicOfficialPMMonitors.Keys.Count; iLstKey++)
                    {
                        dicOfficialPMMonitors[lstKeySpatial[iLstKey]].longitudeLamber = dConvertArraySpatial[2 * iLstKey] / 100.00;
                        dicOfficialPMMonitors[lstKeySpatial[iLstKey]].latitudeLamber = dConvertArraySpatial[2 * iLstKey + 1] / 100.00;
                    }

                    Dictionary<string, string> dicMonitorInModelofficial = new Dictionary<string, string>();
                    GetGridCellMonitors("combine", dicDataPMSSIAGrid, dicDataPMSSIADispersion, ref dicOfficialPMMonitors, ref dicMonitorInModelofficial);
                    foreach (KeyValuePair<string, string> k in dicMonitorInModelofficial)
                    {
                        SSIAAnnualPMDataOutput model = new SSIAAnnualPMDataOutput();
                        if (dicDataPMSSIAGrid.ContainsKey(dicOfficialPMMonitors[k.Key].gridcell))
                            model = dicDataPMSSIAGrid[dicOfficialPMMonitors[k.Key].gridcell];
                        else
                            model = dicDataPMSSIADispersion[dicOfficialPMMonitors[k.Key].gridcell];
                        dicOfficialPMMonitors[k.Key].dicBasePMsec["0"] = model.dicBaselineModel["0"].pm25sec;
                        dicOfficialPMMonitors[k.Key].dicAltPMsec["0"] = model.dicAlternativeModel["0"].pm25sec;
                        dicOfficialPMMonitors[k.Key].dicDeltaPMsec["0"] = model.dicDeltaModel["0"].pm25sec;
                        if (model.dicBaselineModel["0"].pm25 >= 0 && model.dicAlternativeModel["0"].pm25 >= 0)
                        {
                            dicOfficialPMMonitors[k.Key].dicDeltaPM["0"] = model.dicAlternativeModel["0"].pm25 - model.dicBaselineModel["0"].pm25;
                            dicOfficialPMMonitors[k.Key].dicAltPM["0"] = dicOfficialPMMonitors[k.Key].dicAvgOfficialPM["0"] + dicOfficialPMMonitors[k.Key].dicDeltaPM["0"];
                        }
                        else
                        {
                            dicOfficialPMMonitors[k.Key].dicDeltaPM["0"] = 0;
                            dicOfficialPMMonitors[k.Key].dicAltPM["0"] = -9;
                        }
                    }
                    Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitorsTrue = dicOfficialPMMonitors.Where(p => dicMonitorInModelofficial.ContainsKey(p.Key)).ToDictionary(p => p.Key, p => p.Value);
                    SaveSSIAAnnualPMPoint(CommonClass.CurrentBaseScenario, dicOfficialPMMonitorsTrue, "combine");
                    dicOfficialPMMonitorsTrue.Clear();
                    GC.Collect();
                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish computing point: " + CommonClass.TotalTime + " s.");
                    CommonClass.CurrentLog = "Finish computing point: " + CommonClass.TotalTime + " s.";
                    #endregion

                    #region spatial field
                    _beginTime = DateTime.Now;
                    DotSpatial.Topology.Polygon pUSA = CommonClass.generatePolygonWithinUSA("CMAQ");
                    double dInUSA = 16;

                    Dictionary<string, SSIAAnnualPMOfficial> dicPmMonitorsLatLong = new Dictionary<string, SSIAAnnualPMOfficial>();
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicOfficialPMMonitors)
                    {
                        if (!dicPmMonitorsLatLong.ContainsKey(k.Value.longitudeLamber + "," + k.Value.latitudeLamber))
                        {
                            dicPmMonitorsLatLong.Add(k.Value.longitudeLamber + "," + k.Value.latitudeLamber, k.Value);
                        }
                    }
                    Dictionary<string, SSIAAnnualPMDataOutput> dicCombine = new Dictionary<string, SSIAAnnualPMDataOutput>();
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataPMSSIAGrid)
                    {
                        dicCombine.Add(k.Key, k.Value);
                    }
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataPMSSIADispersion)
                    {
                        dicCombine.Add(k.Key, k.Value);
                    }
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicCombine)
                    {
                        if (pUSA.Contains(new DotSpatial.Topology.Point(k.Value.longitudeLamber, k.Value.latitudeLamber)))
                        {
                            dInUSA = 7;
                        }
                        else
                            dInUSA = 15;

                        #region pm values
                        List<double> fsInterPM = new List<double>();
                        fsInterPM.Add(k.Value.longitudeLamber);
                        fsInterPM.Add(k.Value.latitudeLamber);
                        //简化VNA算法：求半径范围内的监测点做VNA，一开始以5个经纬度来算一直达到10个为止
                        Dictionary<string, double> dicDistanceMonitorPM = new Dictionary<string, double>();
                        foreach (KeyValuePair<string, SSIAAnnualPMOfficial> kPM in dicOfficialPMMonitors)
                        {
                            //----------改成extent----
                            double dLongAbs = Math.Abs(kPM.Value.longitude - k.Value.longitude);
                            if (dLongAbs > dInUSA) continue;
                            double dLatAbs = Math.Abs(kPM.Value.latitude - k.Value.lat);
                            if (dLatAbs > dInUSA) continue;
                            if (dLongAbs > dLatAbs)
                            {
                                dicDistanceMonitorPM.Add(kPM.Key, dLongAbs);
                            }
                            else
                            {
                                dicDistanceMonitorPM.Add(kPM.Key, dLatAbs);
                            }
                        }
                        List<KeyValuePair<string, double>> query = new List<KeyValuePair<string, double>>();
                        query = dicDistanceMonitorPM.ToList();
                        bool isSame = false;
                        foreach (KeyValuePair<string, double> kPM in query)
                        {
                            fsInterPM.Add(dicOfficialPMMonitors[kPM.Key].longitudeLamber);
                            fsInterPM.Add(dicOfficialPMMonitors[kPM.Key].latitudeLamber);
                            if (k.Value.longitudeLamber == dicOfficialPMMonitors[kPM.Key].longitudeLamber
                                && k.Value.latitudeLamber == dicOfficialPMMonitors[kPM.Key].latitudeLamber)
                            {
                                isSame = true;
                                break;
                            }
                        }
                        //------------end VNA 简化算法
                        List<double> fsoutPM = new List<double>();
                        if (!isSame)
                        {
                            CommonClass.VoronoiPoints(fsInterPM.ToArray(), ref fsoutPM);
                        }
                        else
                        {
                            fsInterPM.Add(k.Value.longitudeLamber);
                            fsInterPM.Add(k.Value.latitudeLamber);
                        }
                        if (fsoutPM.Count == 0) continue;
                        //----------------calculate neighbor distance----------------
                        Dictionary<string, float> fsoutStringPM = new Dictionary<string, float>();
                        for (int ifsoutPM = 0; ifsoutPM < fsoutPM.Count; ifsoutPM++)
                        {
                            if (ifsoutPM % 2 == 1)
                            {
                                float distance = Convert.ToSingle(Math.Sqrt(Math.Pow(k.Value.longitudeLamber - dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].longitudeLamber, 2) + Math.Pow(k.Value.latitudeLamber - dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].latitudeLamber, 2)));//CommonClass.getDistanceFrom2Point(k.Value.longitude, k.Value.lat, dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].longitude, dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].latitude);
                                fsoutStringPM.Add(dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].id + "," + dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].gridcell, distance);
                            }
                        }
                        if (fsoutStringPM.Count == 0) continue;
                        Dictionary<string, float> dicGradAdjValues = new Dictionary<string, float>();
                        if (annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA)
                            GetGradAdjValues(ref dicGradAdjValues, fsoutStringPM, k.Value.dicBaselineModel, dicCombine);
                        double vnaPM = 0, gvnaPM = 0;
                        //--------calculate vna or evna according to the setting ----------------
                        #region
                        for (int i = 0; i < 5; i++)
                        {
                            if (annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA && annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA)
                            {
                                AnnualVNAEVNA(dicGradAdjValues, "Inverse Distance Weights", 9000000000, ref vnaPM, ref gvnaPM, fsoutStringPM, dicOfficialPMMonitors, i.ToString());
                            }
                            else if (annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA)
                            {
                                AnnualVNA("Inverse Distance Weights", 9000000000, ref vnaPM, fsoutStringPM, dicOfficialPMMonitors, i.ToString());
                            }
                            else if (annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA)
                            {
                                AnnualEVNA(dicGradAdjValues, "Inverse Distance Weights", 9000000000, ref gvnaPM, fsoutStringPM, dicOfficialPMMonitors, i.ToString());
                            }
                            if (k.Value.dicCIAvna.ContainsKey(i.ToString()))
                                k.Value.dicCIAvna[i.ToString()] = vnaPM;// +k.Value.DeltaModel.pm25;
                            else
                                k.Value.dicCIAvna.Add(i.ToString(), vnaPM);
                            if (k.Value.dicCIAevna.ContainsKey(i.ToString()))
                                k.Value.dicCIAevna[i.ToString()] = gvnaPM;// +k.Value.DeltaModel.pm25;
                            else
                                k.Value.dicCIAevna.Add(i.ToString(), gvnaPM);
                            if (dicDataPMSSIAGrid.ContainsKey(k.Key))
                            {
                                if (dicDataPMSSIAGrid[k.Key].dicCIAvna.ContainsKey(i.ToString()))
                                    dicDataPMSSIAGrid[k.Key].dicCIAvna[i.ToString()] = vnaPM;
                                else
                                    dicDataPMSSIAGrid[k.Key].dicCIAvna.Add(i.ToString(), vnaPM);
                                if (dicDataPMSSIAGrid[k.Key].dicCIAevna.ContainsKey(i.ToString()))
                                    dicDataPMSSIAGrid[k.Key].dicCIAevna[i.ToString()] = gvnaPM;
                                else
                                    dicDataPMSSIAGrid[k.Key].dicCIAevna.Add(i.ToString(), gvnaPM);
                            }
                        }
                        #endregion
                        fsoutStringPM.Clear();
                        #endregion
                    }
                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish interpolating Spatial Field: " + CommonClass.TotalTime + " s.");
                    CommonClass.CurrentLog = "Finish interpolating Spatial Field: " + CommonClass.TotalTime + " s.";
                    SaveSSIAAnnualPMData(baseScenario, dicCombine, new Dictionary<string, SSIAAnnualPMDataOutput>(), annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA, annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA, "combine", dicCells);
                    #endregion
                }

                if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly || annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion)
                {
                    #region point
                    _beginTime = DateTime.Now;
                    if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly)
                    {
                        double[] dConvertArraySpatial = null;
                        List<double> lstConvertArraySpatial = new List<double>();
                        List<string> lstKeySpatial = dicOfficialPMMonitors.Keys.ToList();
                        for (int iLstKey = 0; iLstKey < dicOfficialPMMonitors.Keys.Count; iLstKey++)
                        {
                            lstConvertArraySpatial.Add(dicOfficialPMMonitors[lstKeySpatial[iLstKey]].longitude);
                            lstConvertArraySpatial.Add(dicOfficialPMMonitors[lstKeySpatial[iLstKey]].latitude);
                        }
                        dConvertArraySpatial = lstConvertArraySpatial.ToArray();
                        DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArraySpatial, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984,
           ProjectionInfo.FromProj4String(CommonClass.projUSACMAQ), 0, dConvertArraySpatial.Length / 2);
                        for (int iLstKey = 0; iLstKey < dicOfficialPMMonitors.Keys.Count; iLstKey++)
                        {
                            dicOfficialPMMonitors[lstKeySpatial[iLstKey]].longitudeLamber = dConvertArraySpatial[2 * iLstKey] / 100.00;
                            dicOfficialPMMonitors[lstKeySpatial[iLstKey]].latitudeLamber = dConvertArraySpatial[2 * iLstKey + 1] / 100.00;
                        }
                    }
                    Dictionary<string, string> dicMonitorInModelofficial = new Dictionary<string, string>();
                    GetGridCellMonitors("grid", dicDataPMSSIAGrid, null, ref dicOfficialPMMonitors, ref dicMonitorInModelofficial);
                    foreach (KeyValuePair<string, string> k in dicMonitorInModelofficial)
                    {
                        SSIAAnnualPMDataOutput model = dicDataPMSSIAGrid[dicOfficialPMMonitors[k.Key].gridcell];
                        foreach (string quarter in dicOfficialPMMonitors[k.Key].dicAvgOfficialPM.Keys)
                        {
                            dicOfficialPMMonitors[k.Key].dicBasePMsec[quarter] = model.dicBaselineModel.ContainsKey(quarter) ? model.dicBaselineModel[quarter].pm25sec : -9;
                            dicOfficialPMMonitors[k.Key].dicAltPMsec[quarter] = model.dicAlternativeModel.ContainsKey(quarter) ? model.dicAlternativeModel[quarter].pm25sec : -9;
                            dicOfficialPMMonitors[k.Key].dicDeltaPMsec[quarter] = model.dicDeltaModel.ContainsKey(quarter) ? model.dicDeltaModel[quarter].pm25sec : -9;
                            if (model.dicBaselineModel.ContainsKey(quarter) && model.dicAlternativeModel.ContainsKey(quarter) && model.dicBaselineModel[quarter].pm25 >= 0 && model.dicAlternativeModel[quarter].pm25 >= 0)
                            {
                                dicOfficialPMMonitors[k.Key].dicDeltaPM[quarter] = model.dicAlternativeModel[quarter].pm25 - model.dicBaselineModel[quarter].pm25;
                                dicOfficialPMMonitors[k.Key].dicAltPM[quarter] = dicOfficialPMMonitors[k.Key].dicAvgOfficialPM[quarter] + dicOfficialPMMonitors[k.Key].dicDeltaPM[quarter];
                            }
                            else
                            {
                                dicOfficialPMMonitors[k.Key].dicDeltaPM[quarter] = 0;
                                dicOfficialPMMonitors[k.Key].dicAltPM[quarter] = -9;
                            }
                        }
                        #region 旧的方法（选择周围的网格1x1,3x3,5x5,7x7计算future）已不应用于当前的ssia,现在只用1x1-当前所在网格
                        //int Col = Convert.ToInt32(dicOfficialPMMonitors[k.Key].gridcell) / 1000;
                        //int Row = Convert.ToInt32(dicOfficialPMMonitors[k.Key].gridcell) % 1000;
                        //List<string> lstArrond = new List<string>();

                        //-------首先根据gridtype获取周围的网格数
                        #region
                        //switch ("1x1")//annualPMSSIAAnalysisConfiguration.monitorInputA.temporalAdjustmentAtMonitorGrid)
                        //{
                        //    case "1x1":
                        //        lstArrond.Add(dicDataPMSSIAGrid[dicOfficialPMMonitors[k.Key].gridcell].id);
                        //        break;
                        //    case "3x3":
                        //        for (int m3 = -1; m3 <= 1; m3++)
                        //        {
                        //            for (int n3 = -1; n3 <= 1; n3++)
                        //            {
                        //                lstArrond.Add(((Col + m3) * 1000 + (Row + n3)).ToString());
                        //            }
                        //        }
                        //        break;
                        //    case "5x5":
                        //        for (int m5 = -2; m5 <= 2; m5++)
                        //        {
                        //            for (int j5 = -2; j5 <= 2; j5++)
                        //            {
                        //                lstArrond.Add(((Col + m5) * 1000 + (Row + j5)).ToString());
                        //            }
                        //        }
                        //        break;
                        //    case "7x7":
                        //        for (int m7 = -3; m7 <= 3; m7++)
                        //        {
                        //            for (int j7 = -3; j7 <= 3; j7++)
                        //            {
                        //                lstArrond.Add(((Col + m7) * 1000 + (Row + j7)).ToString());
                        //            }
                        //        }
                        //        break;
                        //}
                        #endregion
                        //然后求所有网格的baseline和control的均值,得到delta，然后求future values
                        #region
                        //var query = dicDataPMSSIA.Where(p => lstArrond.Contains(p.Key)).ToList();
                        //if (query.Count() > 0)
                        //{
                        //    if (!annualPMSSIAAnalysisConfiguration.analysisOptionA.useDispersionOnly)
                        //    {
                        //        float baselinePM = 0;
                        //        float altPM = 0;
                        //        //foreach(KeyValuePair<string , SSIAAnnualPMDataOutput> kv in query)
                        //        //{
                        //        //    baselinePM += kv.Value.BaselineModel.pm25;
                        //        //    altPM += kv.Value.AlternativeModel.pm25;
                        //        //}
                        //        var select = query.Where(q => q.Value.BaselineModel.pm25 >= 0);
                        //        if (select.Count() > 0)
                        //            baselinePM = select.Select(q => q.Value.BaselineModel.pm25).ToList().Average();
                        //        else
                        //        {
                        //            dicOfficialPMMonitors[k.Key].deltaPM = 0;
                        //            dicOfficialPMMonitors[k.Key].altPM = -9;
                        //            continue;
                        //        }

                        //        select = query.Where(q => q.Value.AlternativeModel.pm25 >= 0);
                        //        if (select.Count() > 0)
                        //            altPM = select.Select(q => q.Value.AlternativeModel.pm25).ToList().Average();
                        //        else
                        //        {
                        //            dicOfficialPMMonitors[k.Key].deltaPM = 0;
                        //            dicOfficialPMMonitors[k.Key].altPM = -9;
                        //            continue;
                        //        }
                        //        //-----------RRF limitation----------------
                        //        if (baselinePM < CommonClass.RrfLimit) baselinePM = Convert.ToSingle(CommonClass.RrfLimit);
                        //        if (altPM < CommonClass.RrfLimit) altPM = Convert.ToSingle(CommonClass.RrfLimit);

                        //        //dicOfficialPMMonitors[k.Key].altPM = dicOfficialPMMonitors[k.Key].avgOfficialPM * Convert.ToSingle(CommonClass.ToFixed(altPM / baselinePM, 4));
                        //        //dicOfficialPMMonitors[k.Key].deltaPM = dicOfficialPMMonitors[k.Key].altPM - dicOfficialPMMonitors[k.Key].avgOfficialPM;
                        //        dicOfficialPMMonitors[k.Key].deltaPM = altPM - baselinePM;
                        //    }
                        //    else
                        //    {
                        //        dicOfficialPMMonitors[k.Key].deltaPM = query.Select(q => q.Value.DeltaModel.pm25).ToList().Average();
                        //    }
                        //    dicOfficialPMMonitors[k.Key].altPM = dicOfficialPMMonitors[k.Key].avgOfficialPM + dicOfficialPMMonitors[k.Key].deltaPM;
                        //}
                        //else
                        //{
                        //    dicOfficialPMMonitors[k.Key].deltaPM = 0;
                        //    dicOfficialPMMonitors[k.Key].altPM = -9;
                        //}
                        #endregion
                        #endregion
                    }
                    Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitorsTrue = dicOfficialPMMonitors.Where(p => dicMonitorInModelofficial.ContainsKey(p.Key)).ToDictionary(p => p.Key, p => p.Value);
                    SaveSSIAAnnualPMPoint(CommonClass.CurrentBaseScenario, dicOfficialPMMonitorsTrue, "grid");
                    SaveSSIAAnnualPMPoint(CommonClass.CurrentBaseScenario, dicOfficialPMMonitorsTrue, "quarter");
                    dicOfficialPMMonitorsTrue.Clear();
                    GC.Collect();
                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish computing point: " + CommonClass.TotalTime + " s.");
                    CommonClass.CurrentLog = "Finish computing point: " + CommonClass.TotalTime + " s.";
                    #endregion

                    if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridOnly)
                    {
                        #region spatial field
                        _beginTime = DateTime.Now;
                        //List<DotSpatial.Topology.Coordinate> lstUSA = new List<DotSpatial.Topology.Coordinate>();
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(-19131.63, 12011.57));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(-12255.43, 9568.71));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(4075.57, 8573.47));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(10725.59, 3732.98));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(18054.18, 5044.88));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(12173.21, -7486.09));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(-1398.24, -6852.76));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(-12979.23, -5631.33));
                        //lstUSA.Add(new DotSpatial.Topology.Coordinate(-21257.82, 837.73));

                        DotSpatial.Topology.Polygon pUSA = CommonClass.generatePolygonWithinUSA("CMAQ");//new DotSpatial.Topology.Polygon(lstUSA);
                        double dInUSA = 16;

                        Dictionary<string, SSIAAnnualPMOfficial> dicPmMonitorsLatLong = new Dictionary<string, SSIAAnnualPMOfficial>();
                        foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicOfficialPMMonitors)
                        {
                            if (!dicPmMonitorsLatLong.ContainsKey(k.Value.longitudeLamber + "," + k.Value.latitudeLamber))
                            {
                                dicPmMonitorsLatLong.Add(k.Value.longitudeLamber + "," + k.Value.latitudeLamber, k.Value);
                            }
                        }
                        foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataPMSSIAGrid)
                        {
                            if (pUSA.Contains(new DotSpatial.Topology.Point(k.Value.longitudeLamber, k.Value.latitudeLamber)))
                            {
                                dInUSA = 7;
                            }
                            else
                                dInUSA = 15;

                            #region pm values
                            List<double> fsInterPM = new List<double>();
                            fsInterPM.Add(k.Value.longitudeLamber);
                            fsInterPM.Add(k.Value.latitudeLamber);
                            //简化VNA算法：求半径范围内的监测点做VNA，一开始以5个经纬度来算一直达到10个为止
                            Dictionary<string, double> dicDistanceMonitorPM = new Dictionary<string, double>();
                            foreach (KeyValuePair<string, SSIAAnnualPMOfficial> kPM in dicOfficialPMMonitors)
                            {
                                //----------改成extent----
                                double dLongAbs = Math.Abs(kPM.Value.longitude - k.Value.longitude);
                                if (dLongAbs > dInUSA) continue;
                                double dLatAbs = Math.Abs(kPM.Value.latitude - k.Value.lat);
                                if (dLatAbs > dInUSA) continue;
                                if (dLongAbs > dLatAbs)
                                {
                                    dicDistanceMonitorPM.Add(kPM.Key, dLongAbs);
                                }
                                else
                                {
                                    dicDistanceMonitorPM.Add(kPM.Key, dLatAbs);
                                }
                            }
                            List<KeyValuePair<string, double>> query = new List<KeyValuePair<string, double>>();
                            query = dicDistanceMonitorPM.ToList();
                            bool isSame = false;
                            foreach (KeyValuePair<string, double> kPM in query)
                            {
                                fsInterPM.Add(dicOfficialPMMonitors[kPM.Key].longitudeLamber);
                                fsInterPM.Add(dicOfficialPMMonitors[kPM.Key].latitudeLamber);
                                if (k.Value.longitudeLamber == dicOfficialPMMonitors[kPM.Key].longitudeLamber
                                    && k.Value.latitudeLamber == dicOfficialPMMonitors[kPM.Key].latitudeLamber)
                                {
                                    isSame = true;
                                    break;
                                }
                            }
                            //------------end VNA 简化算法
                            List<double> fsoutPM = new List<double>();
                            if (!isSame)
                            {
                                CommonClass.VoronoiPoints(fsInterPM.ToArray(), ref fsoutPM);
                            }
                            else
                            {
                                fsInterPM.Add(k.Value.longitudeLamber);
                                fsInterPM.Add(k.Value.latitudeLamber);
                            }
                            if (fsoutPM.Count == 0) continue;
                            //----------------calculate neighbor distance----------------
                            Dictionary<string, float> fsoutStringPM = new Dictionary<string, float>();
                            for (int ifsoutPM = 0; ifsoutPM < fsoutPM.Count; ifsoutPM++)
                            {
                                if (ifsoutPM % 2 == 1)
                                {
                                    float distance = Convert.ToSingle(Math.Sqrt(Math.Pow(k.Value.longitudeLamber - dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].longitudeLamber, 2) + Math.Pow(k.Value.latitudeLamber - dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].latitudeLamber, 2))); //CommonClass.getDistanceFrom2Point(k.Value.longitude, k.Value.lat, dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].longitude, dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].latitude);
                                    fsoutStringPM.Add(dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].id + "," + dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].gridcell, distance);
                                }
                            }
                            if (fsoutStringPM.Count == 0) continue;
                            Dictionary<string, float> dicGradAdjValues = new Dictionary<string, float>();
                            if (annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA)
                                GetGradAdjValues(ref dicGradAdjValues, fsoutStringPM, k.Value.dicBaselineModel, dicDataPMSSIAGrid);

                            for (int i = 0; i < 5; i++)
                            {
                                double vnaPM = 0, gvnaPM = 0;
                                //--------calculate vna or evna according to the setting ----------------
                                #region
                                if (annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA && annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA)
                                {
                                    AnnualVNAEVNA(dicGradAdjValues, "Inverse Distance Weights", 9000000000, ref vnaPM, ref gvnaPM, fsoutStringPM, dicOfficialPMMonitors, i.ToString());
                                }
                                else if (annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA)
                                {
                                    AnnualVNA("Inverse Distance Weights", 9000000000, ref vnaPM, fsoutStringPM, dicOfficialPMMonitors, i.ToString());
                                }
                                else if (annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA)
                                {
                                    AnnualEVNA(dicGradAdjValues, "Inverse Distance Weights", 9000000000, ref gvnaPM, fsoutStringPM, dicOfficialPMMonitors, i.ToString());
                                }
                                if (k.Value.dicCIAvna.ContainsKey(i.ToString()))
                                    k.Value.dicCIAvna[i.ToString()] = vnaPM;// +k.Value.DeltaModel.pm25;
                                else
                                    k.Value.dicCIAvna.Add(i.ToString(), vnaPM);
                                if (k.Value.dicCIAevna.ContainsKey(i.ToString()))
                                    k.Value.dicCIAevna[i.ToString()] = gvnaPM;// +k.Value.DeltaModel.pm25;
                                else
                                    k.Value.dicCIAevna.Add(i.ToString(), gvnaPM);
                            }
                                #endregion
                            fsoutStringPM.Clear();
                            #endregion
                        }
                        _endTime = DateTime.Now;
                        CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                        CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish interpolating Spatial Field: " + CommonClass.TotalTime + " s.");
                        CommonClass.CurrentLog = "Finish interpolating Spatial Field: " + CommonClass.TotalTime + " s.";
                        #endregion
                    }
                    SaveSSIAAnnualPMData(baseScenario, dicDataPMSSIAGrid, null, annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA, annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA, "grid,quarter", dicCells);
                }

                if (annualPMSSIAAnalysisConfiguration.analysisOptionA.useDispersionOnly || annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion)
                {
                    #region point
                    _beginTime = DateTime.Now;
                    double[] dConvertArraySpatial = null;
                    List<double> lstConvertArraySpatial = new List<double>();
                    List<string> lstKeySpatial = dicOfficialPMMonitors.Keys.ToList();
                    for (int iLstKey = 0; iLstKey < dicOfficialPMMonitors.Keys.Count; iLstKey++)
                    {
                        lstConvertArraySpatial.Add(dicOfficialPMMonitors[lstKeySpatial[iLstKey]].longitude);
                        lstConvertArraySpatial.Add(dicOfficialPMMonitors[lstKeySpatial[iLstKey]].latitude);
                    }
                    dConvertArraySpatial = lstConvertArraySpatial.ToArray();
                    DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArraySpatial, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984,
       ProjectionInfo.FromProj4String(CommonClass.projUSAAERMOD), 0, dConvertArraySpatial.Length / 2);
                    for (int iLstKey = 0; iLstKey < dicOfficialPMMonitors.Keys.Count; iLstKey++)
                    {
                        dicOfficialPMMonitors[lstKeySpatial[iLstKey]].longitudeUTM = (dConvertArraySpatial[2 * iLstKey] - 738547) / 100.00;
                        dicOfficialPMMonitors[lstKeySpatial[iLstKey]].latitudeUTM = (dConvertArraySpatial[2 * iLstKey + 1] - 3724842) / 100.00;
                    }
                    Dictionary<string, string> dicMonitorInModelofficial = new Dictionary<string, string>();
                    GetGridCellMonitors("dispersion", dicDataPMSSIAGrid, dicDataPMSSIADispersion, ref dicOfficialPMMonitors, ref dicMonitorInModelofficial);

                    foreach (KeyValuePair<string, string> k in dicMonitorInModelofficial)
                    {
                        dicOfficialPMMonitors[k.Key].dicDeltaPM["0"] = dicDataPMSSIADispersion[dicOfficialPMMonitors[k.Key].gridcell].dicDeltaModel["0"].pm25prim;
                        dicOfficialPMMonitors[k.Key].dicAltPM["0"] = dicOfficialPMMonitors[k.Key].dicAvgOfficialPM["0"] + dicOfficialPMMonitors[k.Key].dicDeltaPM["0"];
                    }
                    Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitorsTrue = dicOfficialPMMonitors.Where(p => dicMonitorInModelofficial.ContainsKey(p.Key)).ToDictionary(p => p.Key, p => p.Value);
                    SaveSSIAAnnualPMPoint(CommonClass.CurrentBaseScenario, dicOfficialPMMonitorsTrue, "dispersion");
                    dicOfficialPMMonitorsTrue.Clear();
                    GC.Collect();
                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish computing point: " + CommonClass.TotalTime + " s.");
                    CommonClass.CurrentLog = "Finish computing point: " + CommonClass.TotalTime + " s.";
                    #endregion

                    #region spatial field
                    _beginTime = DateTime.Now;
                    //List<DotSpatial.Topology.Coordinate> lstUSA = new List<DotSpatial.Topology.Coordinate>();
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(-19131.63, 12011.57));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(-12255.43, 9568.71));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(4075.57, 8573.47));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(10725.59, 3732.98));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(18054.18, 5044.88));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(12173.21, -7486.09));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(-1398.24, -6852.76));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(-12979.23, -5631.33));
                    //lstUSA.Add(new DotSpatial.Topology.Coordinate(-21257.82, 837.73));

                    DotSpatial.Topology.Polygon pUSA = CommonClass.generatePolygonWithinUSA("AERMOD");
                    double dInUSA = 16;

                    Dictionary<string, SSIAAnnualPMOfficial> dicPmMonitorsLatLong = new Dictionary<string, SSIAAnnualPMOfficial>();
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicOfficialPMMonitors)
                    {
                        if (!dicPmMonitorsLatLong.ContainsKey(k.Value.longitudeUTM + "," + k.Value.latitudeUTM))
                        {
                            dicPmMonitorsLatLong.Add(k.Value.longitudeUTM + "," + k.Value.latitudeUTM, k.Value);
                        }
                    }
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataPMSSIADispersion)
                    {
                        if (pUSA.Contains(new DotSpatial.Topology.Point(k.Value.longitudeUTM, k.Value.latitudeUTM)))
                        {
                            dInUSA = 7;
                        }
                        else
                            dInUSA = 15;

                        #region pm values
                        List<double> fsInterPM = new List<double>();
                        fsInterPM.Add(k.Value.longitudeUTM);
                        fsInterPM.Add(k.Value.latitudeUTM);
                        //简化VNA算法：求半径范围内的监测点做VNA，一开始以5个经纬度来算一直达到10个为止
                        Dictionary<string, double> dicDistanceMonitorPM = new Dictionary<string, double>();
                        foreach (KeyValuePair<string, SSIAAnnualPMOfficial> kPM in dicOfficialPMMonitors)
                        {
                            //----------改成extent----
                            double dLongAbs = Math.Abs(kPM.Value.longitude - k.Value.longitude);
                            if (dLongAbs > dInUSA) continue;
                            double dLatAbs = Math.Abs(kPM.Value.latitude - k.Value.lat);
                            if (dLatAbs > dInUSA) continue;
                            if (dLongAbs > dLatAbs)
                            {
                                dicDistanceMonitorPM.Add(kPM.Key, dLongAbs);
                            }
                            else
                            {
                                dicDistanceMonitorPM.Add(kPM.Key, dLatAbs);
                            }
                        }
                        List<KeyValuePair<string, double>> query = new List<KeyValuePair<string, double>>();
                        query = dicDistanceMonitorPM.ToList();
                        bool isSame = false;
                        foreach (KeyValuePair<string, double> kPM in query)
                        {
                            fsInterPM.Add(dicOfficialPMMonitors[kPM.Key].longitudeUTM);
                            fsInterPM.Add(dicOfficialPMMonitors[kPM.Key].latitudeUTM);
                            if (k.Value.longitudeUTM == dicOfficialPMMonitors[kPM.Key].longitudeUTM
                                && k.Value.latitudeUTM == dicOfficialPMMonitors[kPM.Key].latitudeUTM)
                            {
                                isSame = true;
                                break;
                            }
                        }
                        //------------end VNA 简化算法
                        List<double> fsoutPM = new List<double>();
                        if (!isSame)
                        {
                            CommonClass.VoronoiPoints(fsInterPM.ToArray(), ref fsoutPM);
                        }
                        else
                        {
                            fsInterPM.Add(k.Value.longitudeUTM);
                            fsInterPM.Add(k.Value.latitudeUTM);
                        }
                        if (fsoutPM.Count == 0) continue;
                        //----------------calculate neighbor distance----------------
                        Dictionary<string, float> fsoutStringPM = new Dictionary<string, float>();
                        for (int ifsoutPM = 0; ifsoutPM < fsoutPM.Count; ifsoutPM++)
                        {
                            if (ifsoutPM % 2 == 1)
                            {
                                float distance = Convert.ToSingle(Math.Sqrt(Math.Pow(k.Value.longitudeUTM - dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].longitudeUTM, 2) + Math.Pow(k.Value.latitudeUTM - dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].latitudeUTM, 2)));//CommonClass.getDistanceFrom2Point(k.Value.longitude, k.Value.lat, dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].longitude, dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].latitude);
                                fsoutStringPM.Add(dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].id + "," + dicPmMonitorsLatLong[fsoutPM[ifsoutPM - 1] + "," + fsoutPM[ifsoutPM]].gridcell, distance);
                            }
                        }
                        if (fsoutStringPM.Count == 0) continue;
                        Dictionary<string, float> dicGradAdjValues = new Dictionary<string, float>();
                        double vnaPM = 0;
                        //--------calculate vna or evna according to the setting ----------------
                        #region
                        if (annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA)
                        {
                            AnnualVNA("Inverse Distance Weights", 9000000000, ref vnaPM, fsoutStringPM, dicOfficialPMMonitors, "0");
                        }
                        k.Value.dicCIAvna["0"] = vnaPM;// +k.Value.DeltaModel.pm25;
                        //k.Value.CIAevna = gvnaPM;// +k.Value.DeltaModel.pm25;
                        #endregion
                        fsoutStringPM.Clear();
                        #endregion
                    }
                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish interpolating Spatial Field: " + CommonClass.TotalTime + " s.");
                    CommonClass.CurrentLog = "Finish interpolating Spatial Field: " + CommonClass.TotalTime + " s.";
                    SaveSSIAAnnualPMData(baseScenario, null, dicDataPMSSIADispersion, annualPMSSIAAnalysisConfiguration.monitorInputA.useVNA, annualPMSSIAAnalysisConfiguration.monitorInputA.useEVNA, "dispersion", dicCells);
                    #endregion
                }
                #endregion


                //调整lstoutput顺序
                List<BaseOutput> lstNew = new List<BaseOutput>();
                List<BaseOutput> bo = new List<BaseOutput>();
                string scenarioName = annualPMSSIAAnalysisConfiguration.analysisOptionA.scenarioName + " ";
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Combined annual PM receptor")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Combined annual PM point")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Dispersion annual PM receptor")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Dispersion annual PM point")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Grid annual PM data")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Grid annual PM point")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Grid quarterly PM data")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Grid quarterly PM point")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                bo = baseScenario.lstOutput.Where(q => q.outputName.Substring(scenarioName.Length, q.outputName.Length - scenarioName.Length).Contains("SSIA Source Location")).ToList();
                if (bo.Count > 0) lstNew.Add(bo.First());
                baseScenario.lstOutput = lstNew;
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static string GetModelData(SSIAAnnualPMAnalysisConfiguration annualPMSSIAAnalysisConfiguration, ref Dictionary<string, SSIAAnnualPMDataOutput> dicModelDataPM)
        {
            try
            {
                #region baseline model data
                //Dictionary<string, int> dicDayCount = new Dictionary<string, int>();
                int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iCrustal = -1, iNH4 = -1, iSO4 = -1, iEC = -1, iNO3 = -1, iOC = -1, iPM25 = -1, iCM = -1, iPM25sec = -1;
                Dictionary<string, SSIAAnnualPMGridModelData> dicCMAQdata = new Dictionary<string, SSIAAnnualPMGridModelData>();
                FileStream fs = new FileStream(annualPMSSIAAnalysisConfiguration.modelInputA.baselineModelDataFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                StreamReader sr = new StreamReader(fs, System.Text.Encoding.UTF8);
                try
                {
                    using (StreamReader csv = new StreamReader(fs, System.Text.Encoding.UTF8))
                    {
                        string strLine = csv.ReadLine();
                        string[] strLineArray = csv.ReadLine().Split(new char[] { ',' });
                        int i = 0;
                        //------------get field index------------
                        #region
                        while (i < strLineArray.Length)
                        {
                            string s = strLineArray[i];
                            switch (s.Trim().ToLower().Replace("\"", ""))
                            {
                                case "_id":
                                    iID = i;
                                    break;
                                case "_type":
                                    iType = i;
                                    break;
                                case "lat":
                                    iLat = i;
                                    break;
                                case "long":
                                    iLong = i;
                                    break;
                                case "date":
                                    iDate = i;
                                    break;
                                case "crustal":
                                    iCrustal = i;
                                    break;
                                case "nh4":
                                    iNH4 = i;
                                    break;
                                case "so4":
                                    iSO4 = i;
                                    break;
                                case "ec":
                                    iEC = i;
                                    break;
                                case "no3":
                                    iNO3 = i;
                                    break;
                                case "oc":
                                    iOC = i;
                                    break;
                                case "pm25":
                                    iPM25 = i;
                                    break;
                                case "cm":
                                    iCM = i;
                                    break;
                                case "pm25sec":
                                    iPM25sec = i;
                                    break;
                            }
                            i++;
                        }
                        //判断必须有的列
                        if (iID < 0 || iLat < 0 || iLong < 0 || iPM25 < 0 || (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion && iPM25sec < 0))
                            return "wrongBaseline";
                        #endregion
                        while (strLine != null)
                        {
                            strLine = csv.ReadLine();
                            if (strLine == null) break;
                            //if (baseModelYear == "") baseModelYear = strLineArray[iDate].Replace("\"", "").Substring(0, 4);
                            strLineArray = strLine.Split(new char[] { ',' });
                            if (dicCMAQdata.ContainsKey(strLineArray[iID].Trim().ToString().Replace("\"", "")))
                            {
                                float dCrustal = -9, dNH4 = -9, dSO4 = -9, dEC = -9, dNO3 = -9, dOC = -9, dCM = -9, dPM25sec = -9;
                                if (iCrustal > 0)
                                    dCrustal = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCrustal]));
                                if (iNH4 > 0)
                                    dNH4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNH4]));
                                if (iSO4 > 0)
                                    dSO4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iSO4]));
                                if (iEC > 0)
                                    dEC = Convert.ToSingle(Convert.ToDecimal(strLineArray[iEC]));
                                if (iNO3 > 0)
                                    dNO3 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNO3]));
                                if (iOC > 0)
                                    dOC = Convert.ToSingle(Convert.ToDecimal(strLineArray[iOC]));
                                if (iCM > 0)
                                    dCM = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCM]));
                                if (iPM25sec > 0)
                                    dPM25sec = Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25sec]));
                                dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies.Add(strLineArray[iDate].Substring(4), new float[18] { Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25])), -9, dCrustal, -9, dNH4, -9, dSO4, -9, dEC, -9, dNO3, -9, dOC, -9, dCM, -9, dPM25sec, -9 });
                            }
                            else
                            {
                                dicCMAQdata.Add(strLineArray[iID].Trim().ToString().Replace("\"", ""), new SSIAAnnualPMGridModelData()
                                {
                                    id = strLineArray[iID].Trim().ToString().Replace("\"", ""),
                                    lat = Convert.ToDouble(strLineArray[iLat].ToString()),
                                    longitude = Convert.ToDouble(strLineArray[iLong].ToString()),
                                    lstSpecies = new Dictionary<string, float[]>()
                                });
                                float dCrustal = -9, dNH4 = -9, dSO4 = -9, dEC = -9, dNO3 = -9, dOC = -9, dCM = -9, dPM25sec = -9;
                                if (iCrustal > 0)
                                    dCrustal = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCrustal]));
                                if (iNH4 > 0)
                                    dNH4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNH4]));
                                if (iSO4 > 0)
                                    dSO4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iSO4]));
                                if (iEC > 0)
                                    dEC = Convert.ToSingle(Convert.ToDecimal(strLineArray[iEC]));
                                if (iNO3 > 0)
                                    dNO3 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNO3]));
                                if (iOC > 0)
                                    dOC = Convert.ToSingle(Convert.ToDecimal(strLineArray[iOC]));
                                if (iCM > 0)
                                    dCM = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCM]));
                                if (iPM25sec > 0)
                                    dPM25sec = Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25sec]));
                                dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies.Add(strLineArray[iDate].Substring(4), new float[18] { Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25])), -9, dCrustal, -9, dNH4, -9, dSO4, -9, dEC, -9, dNO3, -9, dOC, -9, dCM, -9, dPM25sec, -9 });
                            }
                        }

                        //double startPercentage = Convert.ToDouble(annualPMSSIAAnalysisConfiguration.calculationOption.startPercentage) * 0.01;
                        //double endPercentage = Convert.ToDouble(annualPMSSIAAnalysisConfiguration.calculationOption.endPercentage) * 0.01;
                        //foreach (KeyValuePair<string, SSIAAnnualPMGridModelData> k in dicCMAQdata)
                        //{
                        //    dicModelDataPM.Add(k.Key, new SSIAAnnualPMDataOutput()
                        //    {
                        //        id = k.Value.id,
                        //        lat =k.Value.lat,
                        //        longitude = k.Value.longitude,
                        //        BaselineModel = new ModelDataSpecies(),
                        //        AlternativeModel = new ModelDataSpecies(),
                        //        DeltaModel = new ModelDataSpecies()
                        //    });

                        //    //Excel-percentile(array,p)算法：将数组array从小到大排序，计算(n-1)*p的整数部分为i，小数部分为j，其中n为数组大小，则percentile的值是：(1-j)*array第i+1个数+j*array第i+2个数。
                        //    k.Value.lstPM25.Sort();
                        //    int startCount = Convert.ToInt32(Math.Floor((k.Value.lstPM25.Count - 1) * startPercentage));
                        //    int endCount = Convert.ToInt32(Math.Ceiling((k.Value.lstPM25.Count - 1) * endPercentage));
                        //    dicModelDataPM[k.Key].BaselineModel.pm25 = k.Value.lstPM25.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iCrustal > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.crustal = k.Value.lstCrustal.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iNH4 > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.nh4 = k.Value.lstNH4.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iSO4 > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.so4 = k.Value.lstSO4.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iEC > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.ec = k.Value.lstEC.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iNO3 > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.no3 = k.Value.lstNO3.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iOC > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.oc = k.Value.lstOC.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iCM > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.cm = k.Value.lstCM.GetRange(startCount, endCount - startCount + 1).Average();
                        //    if (iPM25sec > 0)
                        //        dicModelDataPM[k.Key].BaselineModel.pm25sec = k.Value.lstPM25sec.GetRange(startCount, endCount - startCount + 1).Average();
                        //}
                        #region old
                        //while (strLine != null)
                        //{
                        //    strLine = csv.ReadLine();
                        //    if (strLine == null) break;
                        //    strLineArray = strLine.Split(new char[] { ',' });
                        //    if (dicModelDataPM.ContainsKey(strLineArray[iID].Trim().ToString().Replace("\"", "")))
                        //    {
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.crustal = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.crustal) + Convert.ToDecimal(strLineArray[iCrustal]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.nh4 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.nh4) + Convert.ToDecimal(strLineArray[iNH4]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.so4 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.so4) + Convert.ToDecimal(strLineArray[iSO4]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.oc = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.oc) + Convert.ToDecimal(strLineArray[iOC]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.no3 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.no3) + Convert.ToDecimal(strLineArray[iNO3]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.ec = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.ec) + Convert.ToDecimal(strLineArray[iEC]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.pm25 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.pm25) + Convert.ToDecimal(strLineArray[iPM25]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.cm = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].BaselineModel.cm) + Convert.ToDecimal(strLineArray[iCM]));
                                
                        //        dicDayCount[strLineArray[iID].Trim().ToString().Replace("\"", "")] += 1;
                        //    }
                        //    else
                        //    {
                        //        dicModelDataPM.Add(strLineArray[iID].Trim().ToString().Replace("\"", ""), new SSIAAnnualPMDataOutput()
                        //        {
                        //            id = strLineArray[iID].Trim().ToString().Replace("\"", ""),
                        //            lat = Convert.ToDouble(strLineArray[iLat].ToString()),
                        //            longitude = Convert.ToDouble(strLineArray[iLong].ToString()),
                        //            BaselineModel = new ModelDataSpecies()
                        //            {
                        //                crustal = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCrustal])),
                        //                nh4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNH4])),
                        //                so4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iSO4])),
                        //                oc = Convert.ToSingle(Convert.ToDecimal(strLineArray[iOC])),
                        //                no3 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNO3])),
                        //                ec = Convert.ToSingle(Convert.ToDecimal(strLineArray[iEC])),
                        //                pm25 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25])),
                        //                cm = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCM])),
                        //            },
                        //            AlternativeModel = new ModelDataSpecies()
                        //            {
                        //                crustal = 0,
                        //                nh4 = 0,
                        //                so4 = 0,
                        //                oc = 0,
                        //                no3 = 0,
                        //                ec = 0,
                        //                pm25 = 0,
                        //                cm = 0,
                        //            },
                        //            DeltaModel = new ModelDataSpecies()
                        //            {
                        //                crustal = 0,
                        //                nh4 = 0,
                        //                so4 = 0,
                        //                oc = 0,
                        //                no3 = 0,
                        //                ec = 0,
                        //                pm25 = 0,
                        //                cm = 0,
                        //            },
                        //        });
                        //        dicDayCount[strLineArray[iID].Trim().ToString().Replace("\"", "")] = 1;
                        //    }
                        //}

                        //foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicModelDataPM)
                        //{
                        //    k.Value.BaselineModel.crustal = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.crustal) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.nh4 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.nh4) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.so4 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.so4) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.oc = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.oc) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.no3 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.no3) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.ec = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.ec) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.pm25 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.pm25) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.BaselineModel.cm = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.BaselineModel.cm) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //}
                        //dicDayCount.Clear();

                        #endregion
                        csv.Dispose(); fs.Dispose();
                        GC.Collect();
                    }
                }
                catch
                {
                    return "wrongBaseline";
                }
                GC.Collect();
                #endregion

                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s.";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                _beginTime = DateTime.Now;
                CommonClass.CurrentLog = "Read model data \"" + Path.GetFileName(annualPMSSIAAnalysisConfiguration.modelInputA.alternativeScenarioFile) + "\".";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                #region future model data
                iID = -1; iType = -1; iLat = -1; iLong = -1; iDate = -1; iCrustal = -1; iNH4 = -1; iSO4 = -1; iEC = -1; iNO3 = -1; iOC = -1; iPM25 = -1; iCM = -1;
                fs = new FileStream(annualPMSSIAAnalysisConfiguration.modelInputA.alternativeScenarioFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                sr = new StreamReader(fs, System.Text.Encoding.UTF8);
                try
                {
                    using (StreamReader csv = new StreamReader(fs, System.Text.Encoding.UTF8))
                    {
                        string strLine = csv.ReadLine();
                        string[] strLineArray = csv.ReadLine().Split(new char[] { ',' });
                        int i = 0;
                        //------------get field index------------
                        #region
                        while (i < strLineArray.Length)
                        {
                            string s = strLineArray[i];
                            switch (s.Trim().ToLower().Replace("\"", ""))
                            {
                                case "_id":
                                    iID = i;
                                    break;
                                case "_type":
                                    iType = i;
                                    break;
                                case "lat":
                                    iLat = i;
                                    break;
                                case "long":
                                    iLong = i;
                                    break;
                                case "date":
                                    iDate = i;
                                    break;
                                case "crustal":
                                    iCrustal = i;
                                    break;
                                case "nh4":
                                    iNH4 = i;
                                    break;
                                case "so4":
                                    iSO4 = i;
                                    break;
                                case "ec":
                                    iEC = i;
                                    break;
                                case "no3":
                                    iNO3 = i;
                                    break;
                                case "oc":
                                    iOC = i;
                                    break;
                                case "pm25":
                                    iPM25 = i;
                                    break;
                                case "cm":
                                    iCM = i;
                                    break;
                            }
                            i++;
                        }
                        //判断必须有的列
                        if (iID < 0 || iLat < 0 || iLong < 0 || iPM25 < 0 || (annualPMSSIAAnalysisConfiguration.analysisOptionA.useGridAndDispersion && iPM25sec < 0))
                            return "wrongBaseline";
                        #endregion
                        while (strLine != null)
                        {
                            strLine = csv.ReadLine();
                            if (strLine == null) break;
                            //if (futureModelYear == "") futureModelYear = strLineArray[iDate].Replace("\"", "").Substring(0, 4);
                            strLineArray = strLine.Split(new char[] { ',' });
                            if (dicCMAQdata.ContainsKey(strLineArray[iID].Trim().ToString().Replace("\"", "")))
                            {
                                dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][1] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25]));
                                if (iCrustal > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][3] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCrustal]));
                                if (iNH4 > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][5] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNH4]));
                                if (iSO4 > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][7] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iSO4]));
                                if (iEC > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][9] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iEC]));
                                if (iNO3 > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][11] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNO3]));
                                if (iOC > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][13] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iOC]));
                                if (iCM > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][15] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCM]));
                                if (iPM25sec > 0)
                                    dicCMAQdata[strLineArray[iID].Trim().ToString().Replace("\"", "")].lstSpecies[strLineArray[iDate].Substring(4)][17] = Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25sec]));
                            }
                            else
                            {
                            }
                        }

                        double startPercentage = Convert.ToDouble(annualPMSSIAAnalysisConfiguration.calculationOption.startPercentage) * 0.01;
                        double endPercentage = Convert.ToDouble(annualPMSSIAAnalysisConfiguration.calculationOption.endPercentage) * 0.01;
                        foreach (KeyValuePair<string, SSIAAnnualPMGridModelData> k in dicCMAQdata)
                        {
                            if (!dicModelDataPM.ContainsKey(k.Key))
                            {
                                dicModelDataPM.Add(k.Key, new SSIAAnnualPMDataOutput()
                                {
                                    id = k.Value.id,
                                    lat = k.Value.lat,
                                    longitude = k.Value.longitude,
                                    dicBaselineModel = new Dictionary<string, ModelDataSpecies>(),
                                    dicAlternativeModel = new Dictionary<string, ModelDataSpecies>(),
                                    dicDeltaModel = new Dictionary<string, ModelDataSpecies>(),
                                    dicCIAvna = new Dictionary<string, double>(),
                                    dicCIAevna = new Dictionary<string, double>()
                                });
                            }
                            dicModelDataPM[k.Key].dicCIAvna.Add("0", -9);
                            dicModelDataPM[k.Key].dicCIAevna.Add("0", -9);

                            //k.Value.lstSpecies = k.Value.lstSpecies.OrderBy(q => q.Value[0]).ToDictionary(q => q.Key, q => q.Value);
                            int startCount = Convert.ToInt32(Math.Floor((k.Value.lstSpecies.Where(q => q.Value[0] >= 0).ToList().Count - 1) * startPercentage));
                            int endCount = Convert.ToInt32(Math.Ceiling((k.Value.lstSpecies.Where(q => q.Value[0] >= 0).ToList().Count - 1) * endPercentage));

                            //get quarterly value and select 95%-98% as annual value according to calculation option
                            for (int j = 0; j < 5; j++)
                            {
                                dicModelDataPM[k.Key].dicBaselineModel.Add(j.ToString(), new ModelDataSpecies());
                                dicModelDataPM[k.Key].dicAlternativeModel.Add(j.ToString(), new ModelDataSpecies());
                                dicModelDataPM[k.Key].dicDeltaModel.Add(j.ToString(), new ModelDataSpecies());
                                List<float[]> lstQuarter = new List<float[]>();
                                switch (j)
                                {
                                    case 0:
                                        //Excel-percentile(array,p)算法：将数组array从小到大排序，计算(n-1)*p的整数部分为i，小数部分为j，其中n为数组大小，则percentile的值是：(1-j)*array第i+1个数+j*array第i+2个数。
                                        lstQuarter = k.Value.lstSpecies.Where(q => q.Value[0] >= 0).Select(q => q.Value).OrderBy(q => q[0]).ToList().GetRange(startCount, endCount - startCount + 1).ToList();
                                        break;
                                    case 1:
                                        lstQuarter = k.Value.lstSpecies.Where(q => Convert.ToInt16(q.Key.Substring(0, 2)) <= 3).Select(q => q.Value).ToList();
                                        break;
                                    case 2:
                                        lstQuarter = k.Value.lstSpecies.Where(q => Convert.ToInt16(q.Key.Substring(0, 2)) >= 4 && Convert.ToInt16(q.Key.Substring(0, 2)) <= 6).Select(q => q.Value).ToList();
                                        break;
                                    case 3:
                                        lstQuarter = k.Value.lstSpecies.Where(q => Convert.ToInt16(q.Key.Substring(0, 2)) >= 7 && Convert.ToInt16(q.Key.Substring(0, 2)) <= 9).Select(q => q.Value).ToList();
                                        break;
                                    case 4:
                                        lstQuarter = k.Value.lstSpecies.Where(q => Convert.ToInt16(q.Key.Substring(0, 2)) >= 10).Select(q => q.Value).ToList();
                                        break;
                                }
                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].pm25 = lstQuarter.Select(q => q[0]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].pm25 = lstQuarter.Select(q => q[1]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].pm25 = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].pm25 - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].pm25;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].crustal = lstQuarter.Select(q => q[2]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].crustal = lstQuarter.Select(q => q[3]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].crustal = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].crustal - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].crustal;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].nh4 = lstQuarter.Select(q => q[4]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].nh4 = lstQuarter.Select(q => q[5]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].nh4 = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].nh4 - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].nh4;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].so4 = lstQuarter.Select(q => q[6]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].so4 = lstQuarter.Select(q => q[7]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].so4 = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].so4 - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].so4;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].ec = lstQuarter.Select(q => q[8]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].ec = lstQuarter.Select(q => q[9]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].ec = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].ec - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].ec;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].no3 = lstQuarter.Select(q => q[10]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].no3 = lstQuarter.Select(q => q[11]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].no3 = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].no3 - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].no3;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].oc = lstQuarter.Select(q => q[12]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].oc = lstQuarter.Select(q => q[13]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].oc = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].oc - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].oc;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].cm = lstQuarter.Select(q => q[14]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].cm = lstQuarter.Select(q => q[15]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].cm = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].cm - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].cm;

                                dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].pm25sec = lstQuarter.Select(q => q[16]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].pm25sec = lstQuarter.Select(q => q[17]).Where(q => q >= 0).Average();
                                dicModelDataPM[k.Key].dicDeltaModel[j.ToString()].pm25sec = dicModelDataPM[k.Key].dicAlternativeModel[j.ToString()].pm25sec - dicModelDataPM[k.Key].dicBaselineModel[j.ToString()].pm25sec;
                            }
                        }
                        #region old
                        //while (strLine != null)
                        //{
                        //    strLine = csv.ReadLine();
                        //    if (strLine == null) break;
                        //    strLineArray = strLine.Split(new char[] { ',' });
                        //    if (dicModelDataPM.ContainsKey(strLineArray[iID].Trim().ToString().Replace("\"", "")))
                        //    {
                        //        if (!dicDayCount.ContainsKey(strLineArray[iID].Trim().ToString().Replace("\"", "")))
                        //            dicDayCount.Add(strLineArray[iID].Trim().ToString().Replace("\"", ""), 0);

                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.crustal = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.crustal) + Convert.ToDecimal(strLineArray[iCrustal]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.nh4 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.nh4) + Convert.ToDecimal(strLineArray[iNH4]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.so4 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.so4) + Convert.ToDecimal(strLineArray[iSO4]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.oc = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.oc) + Convert.ToDecimal(strLineArray[iOC]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.no3 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.no3) + Convert.ToDecimal(strLineArray[iNO3]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.ec = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.ec) + Convert.ToDecimal(strLineArray[iEC]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.pm25 = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.pm25) + Convert.ToDecimal(strLineArray[iPM25]));
                        //        dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.cm = Convert.ToSingle(Convert.ToDecimal(dicModelDataPM[strLineArray[iID].Trim().ToString().Replace("\"", "")].AlternativeModel.cm) + Convert.ToDecimal(strLineArray[iCM]));
                        //        dicDayCount[strLineArray[iID].Trim().ToString().Replace("\"", "")] += 1;
                        //    }
                        //    else
                        //    {
                        //        dicModelDataPM.Add(strLineArray[iID].Trim().ToString().Replace("\"", ""), new SSIAAnnualPMDataOutput()
                        //        {
                        //            id = strLineArray[iID].Trim().ToString().Replace("\"", ""),
                        //            lat = Convert.ToDouble(strLineArray[iLat].ToString()),
                        //            longitude = Convert.ToDouble(strLineArray[iLong].ToString()),
                        //            BaselineModel = new ModelDataSpecies()
                        //            {
                        //                crustal = 0,
                        //                nh4 = 0,
                        //                so4 = 0,
                        //                oc = 0,
                        //                no3 = 0,
                        //                ec = 0,
                        //                pm25 = 0,
                        //                cm = 0,
                        //            },
                        //            AlternativeModel = new ModelDataSpecies()
                        //            {
                        //                crustal = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCrustal])),
                        //                nh4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNH4])),
                        //                so4 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iSO4])),
                        //                oc = Convert.ToSingle(Convert.ToDecimal(strLineArray[iOC])),
                        //                no3 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iNO3])),
                        //                ec = Convert.ToSingle(Convert.ToDecimal(strLineArray[iEC])),
                        //                pm25 = Convert.ToSingle(Convert.ToDecimal(strLineArray[iPM25])),
                        //                cm = Convert.ToSingle(Convert.ToDecimal(strLineArray[iCM])),
                        //            },
                        //        });
                        //        dicDayCount[strLineArray[iID].Trim().ToString().Replace("\"", "")] = 1;
                        //    }
                        //}
                        //foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicModelDataPM)
                        //{
                        //    k.Value.AlternativeModel.crustal = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.crustal) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.nh4 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.nh4) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.so4 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.so4) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.oc = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.oc) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.no3 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.no3) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.ec = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.ec) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.pm25 = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.pm25) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));
                        //    k.Value.AlternativeModel.cm = Convert.ToSingle(Math.Round(Convert.ToSingle(Convert.ToDecimal(k.Value.AlternativeModel.cm) / Convert.ToDecimal(dicDayCount[k.Key])), CommonClass.Species_calc_precision));

                        //    k.Value.DeltaModel.crustal = k.Value.AlternativeModel.crustal - k.Value.BaselineModel.crustal;
                        //    k.Value.DeltaModel.nh4 = k.Value.AlternativeModel.nh4 - k.Value.BaselineModel.nh4;
                        //    k.Value.DeltaModel.so4 = k.Value.AlternativeModel.so4 - k.Value.BaselineModel.so4;
                        //    k.Value.DeltaModel.oc = k.Value.AlternativeModel.oc - k.Value.BaselineModel.oc;
                        //    k.Value.DeltaModel.no3 = k.Value.AlternativeModel.no3 - k.Value.BaselineModel.no3;
                        //    k.Value.DeltaModel.ec = k.Value.AlternativeModel.ec - k.Value.BaselineModel.ec;
                        //    k.Value.DeltaModel.pm25 = k.Value.AlternativeModel.pm25 - k.Value.BaselineModel.pm25;
                        //    k.Value.DeltaModel.cm = k.Value.AlternativeModel.cm - k.Value.BaselineModel.cm;
                        //}
                        #endregion
                        dicCMAQdata.Clear();
                        csv.Dispose(); fs.Dispose();
                        GC.Collect();
                    }
                }
                catch
                {
                    return "wrongFuture";
                }
                GC.Collect();
                #endregion
                return "";
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return "unknow";
            }
        }

        public static string GetDispersionModelData(SSIAAnnualPMAnalysisConfiguration annualPMSSIAAnalysisConfiguration, ref Dictionary<string, SSIAAnnualPMDataOutput> dicModelDataPM, int id)
        {
            try
            {
                //int iID = -1, iX = -1, iY = -1, iConc = -1, iZelev = -1, iZhill = -1, iZflag = -1, iAvg = -1, iGrp = -1, iNUM_YRS = -1, iNET_ID = -1;
                FileStream fs = new FileStream(annualPMSSIAAnalysisConfiguration.modelInputA.dispersionFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                StreamReader sr = new StreamReader(fs, System.Text.Encoding.UTF8);
                //List<SSIAAnnualPMDataOutput> lstModel = new List<SSIAAnnualPMDataOutput>();
                try
                {
                    string sLine = "";
                    while (sLine != null)
                    {
                        sLine = sr.ReadLine();
                        if (!string.IsNullOrEmpty(sLine) && sLine.Substring(0, 1) != "*")
                        {
                            sLine = sLine.Trim();
                            sLine = System.Text.RegularExpressions.Regex.Replace(sLine, "\\s+", " ");
                            string[] strs = System.Text.RegularExpressions.Regex.Split(sLine, " ");
                            SSIAAnnualPMDataOutput data = new SSIAAnnualPMDataOutput();
                            data.longitudeUTM = Convert.ToDouble(strs[0]) / 100.0;
                            data.latitudeUTM = Convert.ToDouble(strs[1]) / 100.0;
                            data.dicDeltaModel = new Dictionary<string, ModelDataSpecies>();
                            data.dicDeltaModel.Add("0", new ModelDataSpecies());
                            data.dicDeltaModel["0"].pm25prim = Convert.ToSingle(strs[2]);
                            data.id = (++id).ToString();
                            data.dicCIAvna = new Dictionary<string, double>();
                            data.dicCIAvna.Add("0", -9);
                            data.dicCIAevna = new Dictionary<string, double>();
                            data.dicCIAevna.Add("0", -9);
                            //lstModel.Add(data);
                            dicModelDataPM.Add(id.ToString(), data);
                        }
                    }
                    //List<double> lstX = lstModel.Select(q => q.longitudeLamber).Distinct().ToList();
                    //lstX.Sort();
                    //double xMin = lstX.Min();
                    //double xMax = lstX.Max();
                    //double xStep = xMax - xMin;
                    //for (int i = 1; i < lstX.Count; i++)
                    //{
                    //    if (xStep > lstX[i] - lstX[i - 1])
                    //        xStep = lstX[i] - lstX[i - 1];
                    //}
                    //List<double> lstY = lstModel.Select(q => q.latitudeLamber).Distinct().ToList();
                    //lstY.Sort();
                    //double yMin = lstY.Min();
                    //double yMax = lstY.Max();
                    //double yStep = yMax - yMin;
                    //for (int i = 1; i < lstY.Count; i++)
                    //{
                    //    if (yStep > lstY[i] - lstY[i - 1])
                    //        yStep = lstY[i] - lstY[i - 1];
                    //}
                    //foreach (SSIAAnnualPMDataOutput data in lstModel)
                    //{
                    //    //col*1000+row
                    //    string id = (((data.latitudeLamber - yMin) / yStep + 1) * 1000 + (data.longitudeLamber - xMin) / xStep + 1).ToString();
                    //    data.id = id;
                    //    dicModelDataPM.Add(id, data);
                    //}
                }
                catch
                {
                    return "wrong";
                }
                sr.Close();
                fs.Close();
                GC.Collect();
                return "";
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return "wrong";
            }
        }

        public static string GetOfficialPmMonitors(SSIAAnnualPMAnalysisConfiguration annualPMSSIAAnalysisConfiguration, ref Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitors)
        {
            try
            {
                //field index
                //string errorInfo = "";
                int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iPM25 = -1;
                int iNdays = -1, iSubCode = -1, iComCode = -1, iStateName = -1, iCountyName = -1;
                FileStream fs = new FileStream(annualPMSSIAAnalysisConfiguration.monitorInputA.officialMonitorDataFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                using (StreamReader csv = new StreamReader(fs, System.Text.Encoding.UTF8))
                {
                    string strLine = csv.ReadLine();
                    string[] strLineArray = csv.ReadLine().Split(new char[] { ',' });
                    int i = 0;
                    while (i < strLineArray.Length)
                    {
                        string s = strLineArray[i];
                        switch (s.Trim().ToLower().Replace(" ", "").Replace("\"", ""))
                        {
                            case "_id":
                                iID = i;
                                break;
                            case "_type":
                                iType = i;
                                break;
                            case "lat":
                                iLat = i;
                                break;
                            case "long":
                                iLong = i;
                                break;
                            case "date":
                                iDate = i;
                                break;
                            case "pm25":
                                iPM25 = i;
                                break;
                            case "ndays":
                                iNdays = i;
                                break;
                            case "_substitution_code":
                                iSubCode = i;
                                break;
                            case "completion_code":
                                iComCode = i;
                                break;
                            case "_state_name":
                                iStateName = i;
                                break;
                            case "_county_name":
                                iCountyName = i;
                                break;
                        }
                        i++;
                    }
                    while (strLine != null)
                    {
                        strLine = csv.ReadLine();
                        if (strLine == null) break;
                        //try
                        //{
                        strLineArray = strLine.Split(new char[] { ',' });
                        //首先判断是否满足start year和end year
                        if (Convert.ToInt32(strLineArray[iDate].Replace("\"", "").Substring(0, 4)) >= Convert.ToInt32(annualPMSSIAAnalysisConfiguration.monitorInputA.monitorDataStartYear)
                            && Convert.ToInt32(strLineArray[iDate].Replace("\"", "").Substring(0, 4)) <= Convert.ToInt32(annualPMSSIAAnalysisConfiguration.monitorInputA.monitorDataEndYear))
                        {
                            if (dicOfficialPMMonitors.ContainsKey(strLineArray[iID].ToString().Replace("\"", "")))
                            {
                                try
                                {
                                    dicOfficialPMMonitors[strLineArray[iID].ToString().Replace("\"", "")].dicOfficialPM.Add(strLineArray[iDate].Replace("\"", "").Substring(0, 6), new PMOfficialPoint()
                                    {
                                        date = strLineArray[iDate].Replace("\"", "").Substring(0, 6),
                                        nDays = Convert.ToInt32(strLineArray[iNdays]),
                                        pm = Convert.ToSingle(strLineArray[iPM25]) == -9 ? float.NaN : Convert.ToSingle(strLineArray[iPM25]),
                                        subCode = strLineArray[iSubCode].Replace("\"", ""),
                                        comCode = Convert.ToInt32(strLineArray[iComCode]),
                                    });
                                }
                                catch (Exception)
                                {

                                }

                            }
                            else
                            {
                                dicOfficialPMMonitors.Add(strLineArray[iID].ToString().Replace("\"", ""), new SSIAAnnualPMOfficial()
                                {
                                    id = strLineArray[iID].Replace("\"", ""),
                                    latitude = Convert.ToDouble(strLineArray[iLat]),
                                    longitude = Convert.ToDouble(strLineArray[iLong]),
                                    type = strLineArray[iType].Replace("\"", ""),
                                    stateName = strLineArray[iStateName].Replace("\"", ""),
                                    countyName = strLineArray[iCountyName].Replace("\"", ""),
                                    dicOfficialPM = new Dictionary<string, PMOfficialPoint>(),
                                });
                                dicOfficialPMMonitors[strLineArray[iID].ToString().Replace("\"", "")].dicOfficialPM.Add(strLineArray[iDate].Replace("\"", "").Substring(0, 6), new PMOfficialPoint()
                                {
                                    date = strLineArray[iDate].Replace("\"", "").Substring(0, 6),
                                    nDays = Convert.ToInt32(strLineArray[iNdays]),
                                    pm = Convert.ToSingle(strLineArray[iPM25]) == -9 ? float.NaN : Convert.ToSingle(strLineArray[iPM25]),
                                    subCode = strLineArray[iSubCode].Replace("\"", ""),
                                    comCode = Convert.ToInt32(strLineArray[iComCode]),
                                });
                            }
                        }
                        //}
                        //catch
                        //{
                        //    errorInfo = "errorRow";
                        //}
                    }
                    csv.Dispose(); fs.Dispose();
                    GC.Collect();
                }
                return "";
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return "unknow";
            }

        }

        public static bool SaveSSIAAnnualPMPoint(BaseScenario baseScenario, Dictionary<string, SSIAAnnualPMOfficial> dicAnnualPoint, string type)
        {
            if (!(baseScenario.configuration is SSIAAnnualPMAnalysisConfiguration))
                return false;
            try
            {
                if (!CommonClass.IsBatch)
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName;
                }
                else
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName;
                }
                if (!Directory.Exists(_resultFilePath))
                    System.IO.Directory.CreateDirectory(_resultFilePath);

                int decimaldigits = 8;
                SSIAAnnualPMAnalysisConfiguration annualPMAnalysisConfiguration = baseScenario.configuration as SSIAAnnualPMAnalysisConfiguration;
                DataTable dt = new DataTable();
                string strFile = "";
                if (type == "combine" || type == "grid")
                {
                    dt.Columns.Add("_id");
                    dt.Columns.Add("_type");
                    dt.Columns.Add("_STATE_NAME");
                    dt.Columns.Add("_COUNTY_NAME");
                    dt.Columns.Add("monitor_lat");
                    dt.Columns.Add("monitor_long");
                    dt.Columns.Add("monitor_gridcell");
                    dt.Columns.Add("PM25 (FRM)");//Base_PM25
                    dt.Columns.Add("Alt_PM25");
                    dt.Columns.Add("DeltaPM25");//Delta(Alt-Base)
                    dt.Columns.Add("Base_PM25_2ndary_only");
                    dt.Columns.Add("ALT_PM25_2ndary_only");
                    dt.Columns.Add("DeltaPM25_2ndary_only");

                    dicAnnualPoint = dicAnnualPoint.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicAnnualPoint)
                    {
                        DataRow dr = dt.NewRow();
                        dr[0] = k.Value.id;
                        dr[1] = k.Value.type;
                        dr[2] = k.Value.stateName;
                        dr[3] = k.Value.countyName;
                        dr[4] = Math.Round(k.Value.latitude, 6);
                        dr[5] = Math.Round(k.Value.longitude, 6);
                        dr[6] = k.Value.gridcell;
                        dr[7] = CommonClass.ToFixed(k.Value.dicAvgOfficialPM["0"], decimaldigits);
                        dr[8] = CommonClass.ToFixed(k.Value.dicAltPM["0"], decimaldigits);
                        dr[9] = CommonClass.ToFixed(k.Value.dicDeltaPM["0"], decimaldigits);
                        dr[10] = CommonClass.ToFixed(k.Value.dicBasePMsec["0"], decimaldigits);
                        dr[11] = CommonClass.ToFixed(k.Value.dicAltPMsec["0"], decimaldigits);
                        dr[12] = CommonClass.ToFixed(k.Value.dicDeltaPMsec["0"], decimaldigits);
                        dt.Rows.Add(dr);
                    }
                    if (type == "combine")
                        strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Combined annual PM point.csv";
                    else
                        strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Grid annual PM point.csv";
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Year");
                    BaseOutput baseOutput = new BaseOutput();
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Add(baseOutput);
                }
                else if (type == "quarter")
                {
                    dt.Columns.Add("_id");
                    dt.Columns.Add("_type");
                    dt.Columns.Add("_STATE_NAME");
                    dt.Columns.Add("_COUNTY_NAME");
                    dt.Columns.Add("monitor_lat");
                    dt.Columns.Add("monitor_long");
                    dt.Columns.Add("monitor_gridcell");
                    dt.Columns.Add("quarter");
                    dt.Columns.Add("PM25 (FRM)_q");//Base_PM25
                    dt.Columns.Add("Alt_PM25_q");
                    dt.Columns.Add("DeltaPM25_q");//Delta(Alt-Base)
                    dt.Columns.Add("Base_PM25_2ndary_only_q");
                    dt.Columns.Add("ALT_PM25_2ndary_only_q");
                    dt.Columns.Add("DeltaPM25_2ndary_only_q");

                    dicAnnualPoint = dicAnnualPoint.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicAnnualPoint)
                    {
                        for (int i = 1; i < 5; i++)
                        {
                            if (!k.Value.dicAvgOfficialPM.ContainsKey(i.ToString())) continue;
                            DataRow dr = dt.NewRow();
                            dr[0] = k.Value.id;
                            dr[1] = k.Value.type;
                            dr[2] = k.Value.stateName;
                            dr[3] = k.Value.countyName;
                            dr[4] = Math.Round(k.Value.latitude, 6);
                            dr[5] = Math.Round(k.Value.longitude, 6);
                            dr[6] = k.Value.gridcell;
                            dr[7] = i.ToString();
                            dr[8] = CommonClass.ToFixed(k.Value.dicAvgOfficialPM[i.ToString()], decimaldigits);
                            dr[9] = CommonClass.ToFixed(k.Value.dicAltPM[i.ToString()], decimaldigits);
                            dr[10] = CommonClass.ToFixed(k.Value.dicDeltaPM[i.ToString()], decimaldigits);
                            dr[11] = CommonClass.ToFixed(k.Value.dicBasePMsec[i.ToString()], decimaldigits);
                            dr[12] = CommonClass.ToFixed(k.Value.dicAltPMsec[i.ToString()], decimaldigits);
                            dr[13] = CommonClass.ToFixed(k.Value.dicDeltaPMsec[i.ToString()], decimaldigits);
                            dt.Rows.Add(dr);
                        }
                    }
                    strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Grid quarterly PM point.csv";
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Quarter");
                    BaseOutput baseOutput = new BaseOutput();
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Add(baseOutput);
                }
                else
                {
                    dt.Columns.Add("_id");
                    dt.Columns.Add("_type");
                    dt.Columns.Add("_STATE_NAME");
                    dt.Columns.Add("_COUNTY_NAME");
                    dt.Columns.Add("monitor_lat");
                    dt.Columns.Add("monitor_long");
                    dt.Columns.Add("monitor_gridcell");
                    dt.Columns.Add("PM25 (FRM)");//Base_PM25
                    dt.Columns.Add("Alt_PM25");
                    dt.Columns.Add("DeltaPM25");//Delta(Alt-Base)
                    //dt.Columns.Add("Base_PM25_2ndary_only");
                    //dt.Columns.Add("ALT_PM25_2ndary_only");
                    //dt.Columns.Add("DeltaPM25_2ndary_only");

                    dicAnnualPoint = dicAnnualPoint.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicAnnualPoint)
                    {
                        DataRow dr = dt.NewRow();
                        dr[0] = k.Value.id;
                        dr[1] = k.Value.type;
                        dr[2] = k.Value.stateName;
                        dr[3] = k.Value.countyName;
                        dr[4] = Math.Round(k.Value.latitude, 6);
                        dr[5] = Math.Round(k.Value.longitude, 6);
                        dr[6] = k.Value.gridcell;
                        dr[7] = CommonClass.ToFixed(k.Value.dicAvgOfficialPM["0"], decimaldigits);
                        dr[8] = CommonClass.ToFixed(k.Value.dicAltPM["0"], decimaldigits);
                        dr[9] = CommonClass.ToFixed(k.Value.dicDeltaPM["0"], decimaldigits);
                        //dr[10] = CommonClass.ToFixed(k.Value.basePMsec, decimaldigits);
                        //dr[11] = CommonClass.ToFixed(k.Value.altPMsec, decimaldigits);
                        //dr[12] = CommonClass.ToFixed(k.Value.deltaPMsec, decimaldigits);
                        dt.Rows.Add(dr);
                    }
                    strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Dispersion annual PM point.csv";
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Year");
                    BaseOutput baseOutput = new BaseOutput();
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Add(baseOutput);
                }
                dt.Dispose();
                GC.Collect();
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static bool SaveSSIAAnnualPMData(BaseScenario baseScenario, Dictionary<string, SSIAAnnualPMDataOutput> dicDataGrid, Dictionary<string, SSIAAnnualPMDataOutput> dicDataDispersion, bool outputCIAvna, bool outputCIAevna, string type, Dictionary<string, double[]> dicDistanceFromSource)
        {
            if (!(baseScenario.configuration is SSIAAnnualPMAnalysisConfiguration))
            {
                return false;
            }
            try
            {
                if (!CommonClass.IsBatch)
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName;
                }
                else
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAAnnualPMAnalysisConfiguration).analysisOptionA.scenarioName;
                }
                if (!Directory.Exists(_resultFilePath))
                    System.IO.Directory.CreateDirectory(_resultFilePath);

                string strFile = "";
                int decimaldigits = 8;
                SSIAAnnualPMAnalysisConfiguration annualPMAnalysisConfiguration = baseScenario.configuration as SSIAAnnualPMAnalysisConfiguration;
                DataTable dt = new DataTable();
                DataRow dr = null;

                if (type.Contains("combine"))
                {
                    dt.Columns.Add("_id");
                    dt.Columns.Add("lat");
                    dt.Columns.Add("long");
                    dt.Columns.Add("Base_PM25");
                    dt.Columns.Add("Alt_PM25");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)");//DeltaC(SIA)
                    if (outputCIAevna)
                    {
                        dt.Columns.Add("PM25 (BG_eVNA)");//C(CIA_eVNA)
                        dt.Columns.Add("Alt_PM25 (BG_eVNA)");
                    }
                    if (outputCIAvna)
                    {
                        dt.Columns.Add("PM25 (BG_VNA)");//C(CIA_VNA)
                        dt.Columns.Add("Alt_PM25 (BG_VNA)");
                    }

                    dt.Columns.Add("Base_PM25_prim_only");
                    dt.Columns.Add("ALT_PM25_prim_only");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)_prim_only");
                    dt.Columns.Add("Base_PM25_2ndary_only");
                    dt.Columns.Add("ALT_PM25_2ndary_only");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)_2ndary_only");
                    dt.Columns.Add("Cell center distance from source(km)");

                    //dicData = dicData.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataGrid)
                    {
                        int i = 0;
                        dr = dt.NewRow();
                        dr[i++] = k.Value.id;
                        dr[i++] = Math.Round(k.Value.lat, 6);
                        dr[i++] = Math.Round(k.Value.longitude, 6);
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        if (outputCIAevna)
                        {
                            dr[i++] = Math.Round(k.Value.dicCIAevna["0"], decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicCIAevna["0"] + k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        }
                        if (outputCIAvna)
                        {
                            dr[i++] = Math.Round(k.Value.dicCIAvna["0"], decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicCIAvna["0"] + k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        }
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25 - k.Value.dicBaselineModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25 - k.Value.dicAlternativeModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round((k.Value.dicAlternativeModel["0"].pm25 - k.Value.dicAlternativeModel["0"].pm25sec) - (k.Value.dicBaselineModel["0"].pm25 - k.Value.dicBaselineModel["0"].pm25sec), decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicDeltaModel["0"].pm25sec, decimaldigits);
                        dr[i++] = dicDistanceFromSource[k.Value.id][2];
                        dt.Rows.Add(dr);
                    }
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataDispersion)
                    {
                        int i = 0;
                        dr = dt.NewRow();
                        dr[i++] = k.Value.id;
                        dr[i++] = Math.Round(k.Value.lat, 6);
                        dr[i++] = Math.Round(k.Value.longitude, 6);
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        if (outputCIAevna)
                        {
                            dr[i++] = Math.Round(k.Value.dicCIAevna["0"], decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicCIAevna["0"] + k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        }
                        if (outputCIAvna)
                        {
                            dr[i++] = Math.Round(k.Value.dicCIAvna["0"], decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicCIAvna["0"] + k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        }
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25 - k.Value.dicBaselineModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25 - k.Value.dicAlternativeModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round((k.Value.dicAlternativeModel["0"].pm25 - k.Value.dicAlternativeModel["0"].pm25sec) - (k.Value.dicBaselineModel["0"].pm25 - k.Value.dicBaselineModel["0"].pm25sec), decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicDeltaModel["0"].pm25sec, decimaldigits);
                        dr[i++] = dicDistanceFromSource[k.Value.id][2];
                        dt.Rows.Add(dr);
                    }
                    strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Combined annual PM receptor.csv";
                    BaseOutput baseOutput = new BaseOutput();
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Annual");
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Insert(0, baseOutput);
                }

                if (type.Contains("dispersion"))
                {
                    dt = new DataTable();
                    dt.Columns.Add("_id");
                    dt.Columns.Add("lat");
                    dt.Columns.Add("long");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)");
                    if (outputCIAvna)
                    {
                        dt.Columns.Add("PM25 (BG_VNA)");//C(CIA_VNA)
                        dt.Columns.Add("Alt_PM25 (BG_VNA)");
                        dt.Columns.Add("Cell center distance from source(km)");

                        foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataDispersion)
                        {
                            dr = dt.NewRow();
                            dr[0] = k.Value.id;
                            dr[1] = Math.Round(k.Value.lat, 6);
                            dr[2] = Math.Round(k.Value.longitude, 6);
                            dr[3] = Math.Round(k.Value.dicDeltaModel["0"].pm25prim, decimaldigits);
                            dr[4] = Math.Round(k.Value.dicCIAvna["0"], decimaldigits);
                            dr[5] = Math.Round(k.Value.dicCIAvna["0"] + k.Value.dicDeltaModel["0"].pm25prim, decimaldigits);

                            dr[6] = dicDistanceFromSource[k.Value.id][2];
                            dt.Rows.Add(dr);
                        }
                    }
                    else
                    {
                        dt.Columns.Add("Cell center distance from source(km)");

                        foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataDispersion)
                        {
                            dr = dt.NewRow();
                            dr[0] = k.Value.id;
                            dr[1] = Math.Round(k.Value.lat, 6);
                            dr[2] = Math.Round(k.Value.longitude, 6);
                            dr[3] = Math.Round(k.Value.dicDeltaModel["0"].pm25prim, decimaldigits);
                            dr[4] = dicDistanceFromSource[k.Value.id][2];
                            dt.Rows.Add(dr);
                        }
                    }
                    strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Dispersion annual PM receptor.csv";
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Annual");
                    BaseOutput baseOutput = new BaseOutput();
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Add(baseOutput);
                }

                if (type.Contains("grid"))
                {
                    dt = new DataTable();
                    dt.Columns.Add("_id");
                    dt.Columns.Add("lat");
                    dt.Columns.Add("long");
                    dt.Columns.Add("Base_PM25_2ndary_only");
                    dt.Columns.Add("ALT_PM25_2ndary_only");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)_2ndary_only");
                    dt.Columns.Add("Base_PM25");
                    dt.Columns.Add("Alt_PM25");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)");//DeltaC(SIA)
                    if (outputCIAevna)
                    {
                        dt.Columns.Add("PM25 (BG_eVNA)");//C(CIA_eVNA)
                        dt.Columns.Add("Alt_PM25 (BG_eVNA)");
                    }
                    if (outputCIAvna)
                    {
                        dt.Columns.Add("PM25 (BG_VNA)");//C(CIA_VNA)
                        dt.Columns.Add("Alt_PM25 (BG_VNA)");
                    }                    
                    dt.Columns.Add("Cell center distance from source(km)");


                    //dicData = dicData.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);

                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataGrid)
                    {
                        int i = 0;
                        dr = dt.NewRow();
                        dr[i++] = k.Value.id;
                        dr[i++] = Math.Round(k.Value.lat, 6);
                        dr[i++] = Math.Round(k.Value.longitude, 6);
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicDeltaModel["0"].pm25sec, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicBaselineModel["0"].pm25, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicAlternativeModel["0"].pm25, decimaldigits);
                        dr[i++] = Math.Round(k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        if (outputCIAevna)
                        {
                            dr[i++] = Math.Round(k.Value.dicCIAevna["0"], decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicCIAevna["0"] + k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        }
                        if (outputCIAvna)
                        {
                            dr[i++] = Math.Round(k.Value.dicCIAvna["0"], decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicCIAvna["0"] + k.Value.dicDeltaModel["0"].pm25, decimaldigits);
                        }
                        dr[i++] = dicDistanceFromSource[k.Value.id][2];

                        dt.Rows.Add(dr);
                    }
                    strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Grid annual PM data.csv";
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Annual");
                    BaseOutput baseOutput = new BaseOutput();
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Add(baseOutput);
                }

                if (type.Contains("quarter"))
                {
                    dt = new DataTable();
                    dt.Columns.Add("_id");
                    dt.Columns.Add("lat");
                    dt.Columns.Add("long");
                    dt.Columns.Add("quarter");
                    dt.Columns.Add("Base_PM25_2ndary_only");
                    dt.Columns.Add("ALT_PM25_2ndary_only");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)_2ndary_only");
                    dt.Columns.Add("Base_PM25");
                    dt.Columns.Add("Alt_PM25");
                    dt.Columns.Add("DeltaPM25 (Alt-Base)");//DeltaC(SIA)
                    if (outputCIAevna)
                    {
                        dt.Columns.Add("PM25 (BG_eVNA)");//C(CIA_eVNA)
                        dt.Columns.Add("Alt_PM25 (BG_eVNA)");
                    }
                    if (outputCIAvna)
                    {
                        dt.Columns.Add("PM25 (BG_VNA)");//C(CIA_VNA)
                        dt.Columns.Add("Alt_PM25 (BG_VNA)");
                    }
                    dt.Columns.Add("Cell center distance from source(km)");


                    //dicData = dicData.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);

                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicDataGrid)
                    {
                        for (int quarter = 1; quarter < 5; quarter++)
                        {
                            if (!k.Value.dicBaselineModel.ContainsKey(quarter.ToString())) continue;
                            int i = 0;
                            dr = dt.NewRow();
                            dr[i++] = k.Value.id;
                            dr[i++] = Math.Round(k.Value.lat, 6);
                            dr[i++] = Math.Round(k.Value.longitude, 6);
                            dr[i++] = quarter;
                            dr[i++] = Math.Round(k.Value.dicBaselineModel[quarter.ToString()].pm25sec, decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicAlternativeModel[quarter.ToString()].pm25sec, decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicDeltaModel[quarter.ToString()].pm25sec, decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicBaselineModel[quarter.ToString()].pm25, decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicAlternativeModel[quarter.ToString()].pm25, decimaldigits);
                            dr[i++] = Math.Round(k.Value.dicDeltaModel[quarter.ToString()].pm25, decimaldigits);
                            if (outputCIAevna)
                            {
                                dr[i++] = Math.Round(k.Value.dicCIAevna[quarter.ToString()], decimaldigits);
                                dr[i++] = Math.Round(k.Value.dicCIAevna[quarter.ToString()] + k.Value.dicDeltaModel[quarter.ToString()].pm25, decimaldigits);
                            }
                            if (outputCIAvna)
                            {
                                dr[i++] = Math.Round(k.Value.dicCIAvna[quarter.ToString()], decimaldigits);
                                dr[i++] = Math.Round(k.Value.dicCIAvna[quarter.ToString()] + k.Value.dicDeltaModel[quarter.ToString()].pm25, decimaldigits);
                            }
                            dr[i++] = dicDistanceFromSource[k.Value.id][2];
                            dt.Rows.Add(dr);
                        }
                    }
                    strFile = annualPMAnalysisConfiguration.analysisOptionA.scenarioName + " SSIA Grid quarterly PM data.csv";
                    CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Quarter");
                    BaseOutput baseOutput = new BaseOutput();
                    baseOutput.outputName = strFile.Replace(".csv", "");
                    baseOutput.outputType = "Monitor Network";
                    baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                    if (File.Exists(_resultFilePath + @"\" + strFile))
                    {
                        FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                        baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                    }
                    else
                    {
                        baseOutput.outputSize = 0;
                    }
                    baseScenario.lstOutput.Add(baseOutput);
                }
                dt.Dispose();
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }


        public static bool PMCalculationOfficialChoice(SSIAAnnualPMAnalysisConfiguration annualPMAnalysisConfiguration, Dictionary<string, SSIAAnnualPMOfficial> dicOfficialPMMonitors, List<string> dicDesignValluePeriods, ref Dictionary<string, SSIAAnnualPMOfficial> dicFrmMonitorBaseline)
        {
            try
            {
                Dictionary<string, SSIAAnnualPMOfficial> dicQuarterlyAverageByYear = new Dictionary<string, SSIAAnnualPMOfficial>();
                Dictionary<string, PMOfficialPoint> dic = new Dictionary<string, PMOfficialPoint>();
                foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicOfficialPMMonitors)
                {
                    try
                    {
                        dicQuarterlyAverageByYear.Add(k.Key, new SSIAAnnualPMOfficial()
                        {
                            id = k.Value.id,
                            type = k.Value.type,
                            latitude = k.Value.latitude,
                            longitude = k.Value.longitude,
                            stateName = k.Value.stateName,
                            countyName = k.Value.countyName,
                            dicOfficialPMPeriod = new Dictionary<string, Dictionary<string, PMOfficialPoint>>(),
                            dicOfficialPM = new Dictionary<string, PMOfficialPoint>(),
                        });
                        foreach (string s in dicDesignValluePeriods)
                        {
                            List<string> lstYear = new List<string>();
                            //lstYear.Add(s.Substring(0, s.IndexOf("-")));
                            //lstYear.Add((Convert.ToInt32(s.Substring(0, s.IndexOf("-"))) + 1).ToString());
                            //lstYear.Add(s.Substring(s.IndexOf("-") + 1));
                            for (int j = Convert.ToInt16(s.Substring(0, s.IndexOf("-"))); j <= Convert.ToInt16(s.Substring(s.IndexOf("-") + 1)); j++)
                            {
                                lstYear.Add(j.ToString());
                            }
                            lstYear.Sort();
                            var query = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode);
                            if (query.Count() == 0) continue;
                            for (int i = 1; i <= 4; i++)
                            {
                                dic = new Dictionary<string, PMOfficialPoint>();
                                switch (i)
                                {
                                    case 1:
                                        var pmQuarter1Value = k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "01" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm);
                                        if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.ContainsKey((i).ToString()))
                                        {
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()].Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter1Value.Count() > 0 ? pmQuarter1Value.Average() : float.NaN,
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        else
                                        {
                                            dic.Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter1Value.Count() > 0 ? pmQuarter1Value.Average() : float.NaN,// k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "01" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm).Average(),
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.Add((i).ToString(), dic);
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        break;
                                    case 2:
                                        var pmQuarter2Value = k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "04" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm);
                                        if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.ContainsKey((i).ToString()))
                                        {
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()].Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter2Value.Count() > 0 ? pmQuarter2Value.Average() : float.NaN,
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        else
                                        {

                                            dic.Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter2Value.Count() > 0 ? pmQuarter2Value.Average() : float.NaN,// k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "04" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm).Average(),
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.Add((i).ToString(), dic);
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        break;
                                    case 3:
                                        var pmQuarter3Value = k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "07" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm);
                                        if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.ContainsKey((i).ToString()))
                                        {
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()].Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter3Value.Count() > 0 ? pmQuarter3Value.Average() : float.NaN,
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        else
                                        {

                                            dic.Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter3Value.Count() > 0 ? pmQuarter3Value.Average() : float.NaN,// k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "07" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm).Average(),
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.Add((i).ToString(), dic);
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        break;
                                    case 4:
                                        var pmQuarter4Value = k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "10" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm);
                                        if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.ContainsKey((i).ToString()))
                                        {
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()].Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter4Value.Count() > 0 ? pmQuarter4Value.Average() : float.NaN,//                                                k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "10" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm).Average(),
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        else
                                        {
                                            dic.Add(s, new PMOfficialPoint()
                                            {
                                                pm = pmQuarter4Value.Count() > 0 ? pmQuarter4Value.Average() : float.NaN,// k.Value.dicOfficialPM.Where(p => p.Value.date.Substring(4, 2) == "10" && lstYear.Contains(p.Value.date.Substring(0, 4))).Select(p => p.Value.pm).Average(),
                                                comCode = k.Value.dicOfficialPM.Where(p => lstYear[lstYear.Count - 1] == p.Value.date.Substring(0, 4)).Select(p => p.Value.comCode).First(),
                                            });
                                            dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.Add((i).ToString(), dic);
                                            if (dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 1 && dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].comCode != 2)
                                            {
                                                dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()][s].pm = float.NaN;
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                        for (int i = 1; i <= 4; i++)
                        {
                            if (!dicQuarterlyAverageByYear[k.Key].dicOfficialPM.ContainsKey((i).ToString()))
                                dicQuarterlyAverageByYear[k.Key].dicOfficialPM.Add((i).ToString(), new PMOfficialPoint());

                            if (!dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod.ContainsKey((i).ToString()) || dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()].Where(p => !Double.IsNaN(p.Value.pm)).Select(p => p.Value.pm).Count() == 0)
                                dicQuarterlyAverageByYear[k.Key].dicOfficialPM[Convert.ToString(i)].pm = float.NaN;
                            else
                                dicQuarterlyAverageByYear[k.Key].dicOfficialPM[Convert.ToString(i)].pm = dicQuarterlyAverageByYear[k.Key].dicOfficialPMPeriod[(i).ToString()].Where(p => !Double.IsNaN(p.Value.pm)).Select(p => p.Value.pm).Average();
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
                //------get average value----
                #region
                foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicQuarterlyAverageByYear)
                {
                    try
                    {
                        if (k.Value.dicOfficialPM.Count() >= 4 && !Double.IsNaN(k.Value.dicOfficialPM["1"].pm))
                        {
                            dicFrmMonitorBaseline.Add(k.Key, new SSIAAnnualPMOfficial()
                            {
                                id = k.Value.id,
                                type = k.Value.type,
                                latitude = k.Value.latitude,
                                longitude = k.Value.longitude,
                                stateName = k.Value.stateName,
                                countyName = k.Value.countyName,
                                dicOfficialPMPeriod = new Dictionary<string, Dictionary<string, PMOfficialPoint>>(),
                                dicAvgOfficialPM = new Dictionary<string, float>(),
                                dicBasePMsec = new Dictionary<string, float>(),
                                dicAltPMsec = new Dictionary<string, float>(),
                                dicDeltaPMsec = new Dictionary<string, float>(),
                                dicAltPM = new Dictionary<string, float>(),
                                dicDeltaPM = new Dictionary<string, float>()
                            });
                      
                            var pmValues = k.Value.dicOfficialPM.Where(p => !Double.IsNaN(p.Value.pm)).Select(p => p.Value.pm);                           
                            dicFrmMonitorBaseline[k.Key].dicAvgOfficialPM.Add("0", pmValues.Count()>0?pmValues.Average():float.NaN);
                            dicFrmMonitorBaseline[k.Key].dicAltPM.Add("0", -9);
                            dicFrmMonitorBaseline[k.Key].dicDeltaPM.Add("0", -9);
                            dicFrmMonitorBaseline[k.Key].dicBasePMsec.Add("0", -9);
                            dicFrmMonitorBaseline[k.Key].dicAltPMsec.Add("0", -9);
                            dicFrmMonitorBaseline[k.Key].dicDeltaPMsec.Add("0", -9);

                            foreach (KeyValuePair<string, PMOfficialPoint> quarter in k.Value.dicOfficialPM)
                            {
                                dicFrmMonitorBaseline[k.Key].dicAvgOfficialPM.Add(quarter.Key, quarter.Value.pm);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
                #endregion
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static bool GetGridCellMonitors(string type, Dictionary<string, SSIAAnnualPMDataOutput> dicModelDataPMGrid, Dictionary<string, SSIAAnnualPMDataOutput> dicModelDataPMDispersion, ref Dictionary<string, SSIAAnnualPMOfficial> dicMonitors, ref Dictionary<string, string> dicMonitorInModelofficial)
        {
            try
            {
                if (type == "combine")
                {
                    //得到monitor属于哪个网格--------简单的方法可以判断以最近的点作为它的网格。首先可以求出第一个网格的大小，在小于一倍网格宽度和长度的最大值求最近点
                    double dLon = 0, dLat = 0;
                    int iFirst = Convert.ToInt32(dicModelDataPMGrid.First().Key);
                    if (dicModelDataPMGrid.ContainsKey((((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()))
                    {
                        dLon = Math.Abs(dicModelDataPMGrid[(((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()].longitudeLamber -
                                dicModelDataPMGrid.First().Value.longitudeLamber
                                );
                        dLat = Math.Abs(dicModelDataPMGrid[(((iFirst / 1000)) * 1000 + iFirst % 1000 + 1).ToString()].latitudeLamber -
                            dicModelDataPMGrid.First().Value.latitudeLamber
                            );
                        dLon /= 2; dLat /= 2;
                    }

                    Dictionary<string, SSIAAnnualPMDataOutput> dicCombine = new Dictionary<string, SSIAAnnualPMDataOutput>();
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicModelDataPMGrid)
                    {
                        dicCombine.Add(k.Key, k.Value);
                    }
                    foreach (KeyValuePair<string, SSIAAnnualPMDataOutput> k in dicModelDataPMDispersion)
                    {
                        dicCombine.Add(k.Key, k.Value);
                    }
                    //---------计算两个网格之内；然后属于哪个的网格，根据距离判断属于哪个网格
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicMonitors)
                    {
                        try
                        {
                            var query = dicCombine.Where(p => Math.Abs(p.Value.longitudeLamber - k.Value.longitudeLamber) < dLon && Math.Abs(p.Value.latitudeLamber - k.Value.latitudeLamber) < dLat).ToList();
                            string sModelIDTemp = "";
                            if (query.Count() > 0)
                            {
                                DotSpatial.Topology.Coordinate coor = new DotSpatial.Topology.Coordinate(k.Value.longitudeLamber, k.Value.latitudeLamber);
                                sModelIDTemp = query.OrderBy(p => Math.Pow(p.Value.longitudeLamber - k.Value.longitudeLamber, 2) + Math.Pow(p.Value.latitudeLamber - k.Value.latitudeLamber, 2)).First().Key;
                                dicMonitorInModelofficial.Add(k.Key, sModelIDTemp);
                            }
                            else
                            {
                                sModelIDTemp = dicCombine.OrderBy(p => Math.Pow(p.Value.longitudeLamber - k.Value.longitudeLamber, 2) + Math.Pow(p.Value.latitudeLamber - k.Value.latitudeLamber, 2)).First().Key;
                            }
                            k.Value.gridcell = sModelIDTemp;
                        }
                        catch
                        {
                        }
                    }
                    dicCombine.Clear();
                }
                else if (type == "grid")
                {
                    //得到monitor属于哪个网格--------简单的方法可以判断以最近的点作为它的网格。首先可以求出第一个网格的大小，在小于一倍网格宽度和长度的最大值求最近点
                    double dLon = 0, dLat = 0;
                    int iFirst = Convert.ToInt32(dicModelDataPMGrid.First().Key);
                    if (dicModelDataPMGrid.ContainsKey((((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()))
                    {
                        dLon = Math.Abs(dicModelDataPMGrid[(((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()].longitudeLamber -
                                dicModelDataPMGrid.First().Value.longitudeLamber
                                );
                        dLat = Math.Abs(dicModelDataPMGrid[(((iFirst / 1000)) * 1000 + iFirst % 1000 + 1).ToString()].latitudeLamber -
                            dicModelDataPMGrid.First().Value.latitudeLamber
                            );
                        dLon /= 2; dLat /= 2;
                    }

                    //---------计算两个网格之内；然后属于哪个的网格，根据距离判断属于哪个网格
                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicMonitors)
                    {
                        try
                        {
                            var query = dicModelDataPMGrid.Where(p => Math.Abs(p.Value.longitudeLamber - k.Value.longitudeLamber) < dLon && Math.Abs(p.Value.latitudeLamber - k.Value.latitudeLamber) < dLat).ToList();
                            string sModelIDTemp = "";
                            if (query.Count() > 0)
                            {
                                DotSpatial.Topology.Coordinate coor = new DotSpatial.Topology.Coordinate(k.Value.longitudeLamber, k.Value.latitudeLamber);
                                sModelIDTemp = query.OrderBy(p => Math.Pow(p.Value.longitudeLamber - k.Value.longitudeLamber, 2) + Math.Pow(p.Value.latitudeLamber - k.Value.latitudeLamber, 2)).First().Key;
                                dicMonitorInModelofficial.Add(k.Key, sModelIDTemp);
                            }
                            else
                            {
                                sModelIDTemp = dicModelDataPMGrid.OrderBy(p => Math.Pow(p.Value.longitudeLamber - k.Value.longitudeLamber, 2) + Math.Pow(p.Value.latitudeLamber - k.Value.latitudeLamber, 2)).First().Key;
                            }
                            k.Value.gridcell = sModelIDTemp;
                        }
                        catch
                        {
                        }
                    }
                }
                else if (type == "dispersion")
                {
                    double dLon = 0, dLat = 0;
                    //int iFirst = Convert.ToInt32(dicModelDataPM.First().Key);
                    //int iLast = Convert.ToInt32(dicModelDataPM.Last().Key);
                    //dLon = Math.Abs(dicModelDataPM[iFirst.ToString()].longitudeLamber - dicModelDataPM[iLast.ToString()].longitudeLamber) / Math.Abs(iFirst / 1000 - iLast / 1000) * 5;//要看aermod网格怎么排列，这个是最外围的网格的最大距离
                    //dLat = Math.Abs(dicModelDataPM[iFirst.ToString()].latitudeLamber - dicModelDataPM[iLast.ToString()].latitudeLamber) / Math.Abs(iFirst % 1000 - iLast % 1000) * 5;
                    List<double> lstLat = dicModelDataPMDispersion.Select(q => q.Value.latitudeUTM).ToList();
                    List<double> lstLon = dicModelDataPMDispersion.Select(q => q.Value.longitudeUTM).ToList();
                    lstLat.Sort();
                    lstLon.Sort();
                    for (int i = 0; i < lstLat.Count - 1; i++)
                    {
                        dLat = Math.Max(dLat, lstLat[i + 1] - lstLat[i]);
                    }
                    for (int i = 0; i < lstLon.Count - 1; i++)
                    {
                        dLon = Math.Max(dLat, lstLon[i + 1] - lstLon[i]);
                    }
                    dLat = dLat / 2;
                    dLon = dLon / 2;
                    lstLat.Clear();
                    lstLon.Clear();

                    foreach (KeyValuePair<string, SSIAAnnualPMOfficial> k in dicMonitors)
                    {
                        try
                        {
                            var query = dicModelDataPMDispersion.Where(p => Math.Abs(p.Value.longitudeUTM - k.Value.longitudeUTM) < dLon && Math.Abs(p.Value.latitudeUTM - k.Value.latitudeUTM) < dLat).ToList();
                            string sModelIDTemp = "";
                            if (query.Count() > 0)
                            {
                                DotSpatial.Topology.Coordinate coor = new DotSpatial.Topology.Coordinate(k.Value.longitudeUTM, k.Value.latitudeUTM);
                                sModelIDTemp = query.OrderBy(p => Math.Pow(p.Value.longitudeUTM - k.Value.longitudeUTM, 2) + Math.Pow(p.Value.latitudeUTM - k.Value.latitudeUTM, 2)).First().Key;
                                dicMonitorInModelofficial.Add(k.Key, sModelIDTemp);
                            }
                            else
                            {
                                sModelIDTemp = dicModelDataPMDispersion.OrderBy(p => Math.Pow(p.Value.longitudeUTM - k.Value.longitudeUTM, 2) + Math.Pow(p.Value.latitudeUTM - k.Value.latitudeUTM, 2)).First().Key;
                                //dicMonitorInModelofficial.Add(k.Key, sModelIDTemp);//test
                            }
                            k.Value.gridcell = sModelIDTemp;
                        }
                        catch
                        {
                        }
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static bool GetGradAdjValues(ref Dictionary<string, float> dicGradAdjValues, Dictionary<string, float> fsoutStringPM, Dictionary<string, ModelDataSpecies> dicBaselineModel, Dictionary<string, SSIAAnnualPMDataOutput> dicModelDataPM)
        {
            try
            {
                foreach (KeyValuePair<string, float> s in fsoutStringPM)
                {
                    string id = s.Key.Substring(0, s.Key.IndexOf(","));
                    string gridcell = s.Key.Substring(s.Key.IndexOf(",") + 1);
                    for (int i = 0; i < 5; i++)
                    {
                        float pm25 = dicBaselineModel[i.ToString()].pm25 / dicModelDataPM[gridcell].dicBaselineModel[i.ToString()].pm25;
                        dicGradAdjValues.Add(s.Key + "," + i.ToString(), pm25);
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static bool AnnualVNA(string interpolationMethod, double distanceInterpolation, ref double dVNA, Dictionary<string, float> fsoutStringPM, Dictionary<string, SSIAAnnualPMOfficial> dicMonitors, string quarter)
        {
            try
            {
                double distanceSpecies = 0, distanceSumSpecies = 0, vnaSum = 0;
                int n = 0;
                switch (interpolationMethod)
                {
                    case "Equal Weighting of Monitors":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                n++;
                                vnaSum += dicMonitors[id].dicAvgOfficialPM[quarter];
                            }
                            catch { }
                        }
                        try
                        {
                            dVNA = Math.Round(Double.IsNaN(vnaSum / n) ? 0 : vnaSum / n, CommonClass.Species_calc_precision);
                        }
                        catch
                        { }
                        #endregion
                        break;
                    case "Inverse Distance Weights":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                distanceSpecies = s.Value == 0 ? 1 : Convert.ToSingle(1.0000 / s.Value);
                                distanceSumSpecies += distanceSpecies;
                                vnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies;
                            }
                            catch
                            { }
                        }
                        try
                        {
                            dVNA = Math.Round(Double.IsNaN(vnaSum / distanceSumSpecies) ? 0 : vnaSum / distanceSumSpecies, CommonClass.Species_calc_precision);
                        }
                        catch
                        { }
                        #endregion
                        break;
                    case "Inverse Distance Squared Weights":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                distanceSpecies = s.Value == 0 ? 1 : Convert.ToSingle(1.0000 / Math.Pow(s.Value, 2));
                                distanceSumSpecies += distanceSpecies;
                                vnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies;
                            }
                            catch
                            {
                            }
                        }
                        try
                        {
                            double d = Double.IsNaN(vnaSum / distanceSumSpecies) ? 0 : vnaSum / distanceSumSpecies;
                            dVNA = Math.Round(Double.IsNaN(vnaSum / distanceSumSpecies) ? 0 : vnaSum / distanceSumSpecies, CommonClass.Species_calc_precision);
                        }
                        catch
                        { }
                        #endregion
                        break;
                }
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static bool AnnualEVNA(Dictionary<string, float> dicGradAdjValues, string interpolationMethod, double distanceInterpolation, ref double dEVNA, Dictionary<string, float> fsoutStringPM, Dictionary<string, SSIAAnnualPMOfficial> dicMonitors, string quarter)
        {
            try
            {
                double distanceSpecies = 0, distanceSumSpecies = 0, gvnaSum = 0;
                int n = 0;
                switch (interpolationMethod)
                {
                    case "Equal Weighting of Monitors":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                n++;
                                gvnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * dicGradAdjValues[s.Key + "," + quarter];
                            }
                            catch { }
                        }
                        try
                        {
                            dEVNA = Math.Round(Double.IsNaN(gvnaSum / n) ? 0 : gvnaSum / n, CommonClass.Species_calc_precision);
                        }
                        catch
                        {
                        }
                        #endregion
                        break;
                    case "Inverse Distance Weights":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                distanceSpecies = s.Value == 0 ? 1 : 1.0000 / s.Value;
                                distanceSumSpecies += distanceSpecies;
                                gvnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies * dicGradAdjValues[s.Key + "," + quarter];
                            }
                            catch { }
                        }
                        try
                        {
                            dEVNA = Math.Round(Double.IsNaN(gvnaSum / distanceSumSpecies) ? 0 : Convert.ToSingle(gvnaSum / distanceSumSpecies), CommonClass.Species_calc_precision);
                        }
                        catch { }
                        #endregion
                        break;
                    case "Inverse Distance Squared Weights":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                distanceSpecies = s.Value == 0 ? 1 : 1.0000 / Math.Pow(s.Value, 2);
                                distanceSumSpecies += distanceSpecies;
                                gvnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies * dicGradAdjValues[s.Key + "," + quarter];
                            }
                            catch
                            {
                            }
                        }
                        try
                        {
                            dEVNA = Math.Round(Double.IsNaN(gvnaSum / distanceSumSpecies) ? 0 : Convert.ToSingle(gvnaSum / distanceSumSpecies), CommonClass.Species_calc_precision);
                        }
                        catch { }
                        #endregion
                        break;
                }
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static bool AnnualVNAEVNA(Dictionary<string, float> dicGradAdjValues, string interpolationMethod, double distanceInterpolation, ref double dVNA, ref double dEVNA, Dictionary<string, float> fsoutStringPM, Dictionary<string, SSIAAnnualPMOfficial> dicMonitors, string quarter)
        {
            try
            {
                double distanceSpecies = 0, distanceSumSpecies = 0, vnaSum = 0, gvnaSum = 0;
                int n = 0;
                Dictionary<string, float> dic = new Dictionary<string, float>();
                switch (interpolationMethod)
                {
                    case "Equal Weighting of Monitors":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                n++;
                                vnaSum += dicMonitors[id].dicAvgOfficialPM[quarter];
                                gvnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * dicGradAdjValues[s.Key + "," + quarter];
                            }
                            catch { }
                        }
                        try
                        {
                            dVNA = Math.Round(Double.IsNaN(vnaSum / n) ? 0 : vnaSum / n, CommonClass.Species_calc_precision);
                            dEVNA = Math.Round(Double.IsNaN(gvnaSum / n) ? 0 : gvnaSum / n, CommonClass.Species_calc_precision);
                        }
                        catch { }
                        #endregion
                        break;
                    case "Inverse Distance Weights":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                distanceSpecies = s.Value == 0 ? 1 : 1.0000 / s.Value;
                                distanceSumSpecies += distanceSpecies;
                                vnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies;
                                gvnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies * dicGradAdjValues[s.Key + "," + quarter];
                            }
                            catch { }
                        }
                        try
                        {
                            dVNA = Math.Round(Double.IsNaN(vnaSum / distanceSumSpecies) ? 0 : vnaSum / distanceSumSpecies, CommonClass.Species_calc_precision);
                            dEVNA = Math.Round(Double.IsNaN(gvnaSum / distanceSumSpecies) ? 0 : gvnaSum / distanceSumSpecies, CommonClass.Species_calc_precision);
                        }
                        catch { }
                        #endregion
                        break;
                    case "Inverse Distance Squared Weights":
                        #region
                        foreach (KeyValuePair<string, float> s in fsoutStringPM)
                        {
                            string id = s.Key.Substring(0, s.Key.IndexOf(","));
                            if (s.Value > distanceInterpolation) continue;
                            try
                            {
                                if ((!dicMonitors.ContainsKey(id) || float.IsNaN(dicMonitors[id].dicAvgOfficialPM[quarter]))) continue;
                                distanceSpecies = s.Value == 0 ? 1 : 1.0000 / Math.Pow(s.Value, 2);
                                distanceSumSpecies += distanceSpecies;
                                vnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies;
                                gvnaSum += dicMonitors[id].dicAvgOfficialPM[quarter] * distanceSpecies * dicGradAdjValues[s.Key + "," + quarter];
                            }
                            catch
                            {
                            }
                        }
                        try
                        {
                            dVNA = Math.Round(Double.IsNaN(vnaSum / distanceSumSpecies) ? 0 : vnaSum / distanceSumSpecies, CommonClass.Species_calc_precision);
                            dEVNA = Math.Round(Double.IsNaN(gvnaSum / distanceSumSpecies) ? 0 : gvnaSum / distanceSumSpecies, CommonClass.Species_calc_precision);
                        }
                        catch { }
                        #endregion
                        break;
                }
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }
        #endregion

        #region SSIA Ozone
        public static bool OzoneAnalysisSSIA(BaseScenario baseScenario, SMAT_CE mats)
        {
            if (!(baseScenario.configuration is SSIAOzoneAnalysisConfiguration))
            {
                return false;
            }
            try
            {
                _beginTime = DateTime.Now;
                SSIAOzoneAnalysisConfiguration ozoneAnalysisConfiguration = baseScenario.configuration as SSIAOzoneAnalysisConfiguration;
                if (!CommonClass.IsBatch)
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName;
                }
                else
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName;
                }
                if (!Directory.Exists(_resultFilePath))
                    System.IO.Directory.CreateDirectory(_resultFilePath);

                CommonClass.CurrentLog = "Read model data \"" + Path.GetFileName(ozoneAnalysisConfiguration.modelInputO.baselineModelDataFile) + "\".";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                #region Read OzoneModel Base from csv //save to dicOzoneDataOutput
                _beginTime = DateTime.Now;
                int iID = -1, iType = -1, iLat = -1, iLong = -1, iO3 = -1;
                int iDate = -1;
                Dictionary<string, SSIAOzoneData> dicOzoneDataOutput = new Dictionary<string, SSIAOzoneData>();
                FileStream fs = new FileStream(ozoneAnalysisConfiguration.modelInputO.baselineModelDataFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                try
                {
                    using (StreamReader csv = new StreamReader(fs, System.Text.Encoding.UTF8))
                    {
                        string strLine = csv.ReadLine();
                        string[] strLineArray = csv.ReadLine().Split(new char[] { ',' });
                        int i = 0;
                        while (i < strLineArray.Length)
                        {
                            string s = strLineArray[i];
                            switch (s.Trim().ToLower())
                            {
                                case "_id":
                                    iID = i;
                                    break;
                                case "_type":
                                    iType = i;
                                    break;
                                case "lat":
                                    iLat = i;
                                    break;
                                case "long":
                                    iLong = i;
                                    break;
                                case "date":
                                    iDate = i;
                                    break;
                                case "o3":
                                    iO3 = i;
                                    break;

                            }
                            i++;
                        }
                        while (strLine != null)
                        {
                            strLine = csv.ReadLine();
                            if (strLine == null) break;
                            strLineArray = strLine.Split(new char[] { ',' });
                            //if (strLineArray[iDate].Substring(0, 4) != startYear) continue;
                            if (dicOzoneDataOutput.ContainsKey(strLineArray[iID].ToString().Trim()))//strLineArray[iDate].Substring(0, 4)))
                            {
                                try
                                {
                                    dicOzoneDataOutput[strLineArray[iID].ToString().Trim()].lstOzone.Add(strLineArray[iDate].Substring(4), new float[2] { Convert.ToSingle(strLineArray[iO3]), -9 });
                                }
                                catch
                                {
                                }
                            }
                            else
                            {
                                dicOzoneDataOutput.Add(strLineArray[iID].ToString().Trim(), new SSIAOzoneData()
                                {
                                    Date = strLineArray[iDate].Substring(0, 4),
                                    id = strLineArray[iID],
                                    lat = Convert.ToDouble(strLineArray[iLat]),
                                    longitude = Convert.ToDouble(strLineArray[iLong]),
                                    type = strLineArray[iType],
                                    lstOzone = new Dictionary<string, float[]>(),
                                    // lstOzoneForecast = new Dictionary<string, float>(),
                                });
                                dicOzoneDataOutput[strLineArray[iID].ToString().Trim()].lstOzone.Add(strLineArray[iDate].Substring(4), new float[2] { Convert.ToSingle(strLineArray[iO3]), -9 });
                            }

                        }
                        csv.Dispose();
                        fs.Dispose();
                    }
                }
                catch
                {
                    CommonClass.CurrentLog = "Fail to read model data \"" + Path.GetFileName(ozoneAnalysisConfiguration.modelInputO.baselineModelDataFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    return false;
                }
                GC.Collect();
                #endregion

                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s.";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                _beginTime = DateTime.Now;
                CommonClass.CurrentLog = "Read model data \"" + Path.GetFileName(ozoneAnalysisConfiguration.modelInputO.forecastModelDataFile) + "\".";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);

                #region Read OzoneModel Control from csv
                _beginTime = DateTime.Now;
                iID = -1; iType = -1; iLat = -1; iLong = -1; iO3 = -1;
                iDate = -1;
                fs = new FileStream(ozoneAnalysisConfiguration.modelInputO.forecastModelDataFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                try
                {
                    using (StreamReader csv = new StreamReader(fs, System.Text.Encoding.UTF8))
                    {
                        string strLine = csv.ReadLine();
                        string[] strLineArray = csv.ReadLine().Split(new char[] { ',' });
                        int i = 0;
                        while (i < strLineArray.Length)
                        {
                            string s = strLineArray[i];
                            switch (s.Trim().ToLower())
                            {
                                case "_id":
                                    iID = i;
                                    break;
                                case "_type":
                                    iType = i;
                                    break;
                                case "lat":
                                    iLat = i;
                                    break;
                                case "long":
                                    iLong = i;
                                    break;
                                case "date":
                                    iDate = i;
                                    break;
                                case "o3":
                                    iO3 = i;
                                    break;

                            }
                            i++;
                        }
                        string _strid = "";
                        while (strLine != null)
                        {
                            strLine = csv.ReadLine();
                            if (strLine == null) break;
                            strLineArray = strLine.Split(new char[] { ',' });
                            //if (strLineArray[iDate].Substring(0, 4) != startYear) continue;
                            //if (lastYear == "") lastYear = strLineArray[iDate].Substring(0, 4);
                            _strid=strLineArray[iID].ToString().Trim();
                            if (dicOzoneDataOutput.ContainsKey(_strid))
                            {
                                //dicOzoneModel[strLineArray[iID].ToString().Trim()].lstOzoneForecast.Add(strLineArray[iDate].Substring(4), Convert.ToSingle(strLineArray[iO3]));
                                float f = Convert.ToSingle(strLineArray[iO3]);
                                dicOzoneDataOutput[_strid].lstOzone[strLineArray[iDate].Substring(4)][1] = f;// Convert.ToSingle(strLineArray[iO3]);
                            }
                            else
                            {

                            }

                        }
                        csv.Dispose();
                        fs.Dispose();
                    }
                }
                catch
                {
                    CommonClass.CurrentLog = "Fail to read model data \"" + Path.GetFileName(ozoneAnalysisConfiguration.modelInputO.forecastModelDataFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    return false;
                }
                GC.Collect();
                #endregion

                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s.";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                _beginTime = DateTime.Now;

                //change project - write in dictionary (lat,long to lambert) - for draw map
                DataTable dt = new DataTable();
                dt.Columns.Add("id");
                dt.Columns.Add("lat");
                dt.Columns.Add("long");
                foreach (KeyValuePair<string, SSIAOzoneData> keyvalue in dicOzoneDataOutput)
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = keyvalue.Key;
                    dr[1] = keyvalue.Value.lat;
                    dr[2] = keyvalue.Value.longitude;
                    dt.Rows.Add(dr);
                }
                mats.changeProject(dt, "USA");

                foreach (KeyValuePair<string, SSIAOzoneData> k in dicOzoneDataOutput)
                {
                    getAvgandSrfOfOzoneModel(k.Value, ozoneAnalysisConfiguration);
                }
                //_endTime = DateTime.Now;
                //CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                //CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish reading model data: " + CommonClass.TotalTime + " s.");
                //CommonClass.CurrentLog = "Finish reading model data: " + CommonClass.TotalTime + " s";
                //_beginTime = DateTime.Now;

                #region Calculate cell center distance from source
                Dictionary<string, double[]> dicCells = new Dictionary<string, double[]>();
                foreach (var item in dicOzoneDataOutput)
                {
                    double[] v = new double[3] { item.Value.lat, item.Value.longitude, 0 };
                    dicCells.Add(item.Value.id, v);
                }
                #region Read Source File
                Dictionary<string, double[]> dicSource = new Dictionary<string, double[]>();
                FileStream fs2 = new FileStream(ozoneAnalysisConfiguration.modelInputO.SourceCoordinateFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                using (StreamReader csv = new StreamReader(fs2, System.Text.Encoding.UTF8))
                {
                    string strLine = csv.ReadLine();//header
                    strLine = csv.ReadLine();
                    string[] strLineArray;
                    while (strLine != null)
                    {
                        strLineArray = strLine.Split(new char[] { ',' });
                        double[] v = new double[2] { Convert.ToDouble(strLineArray[1]), Convert.ToDouble(strLineArray[2]) };
                        dicSource.Add(strLineArray[0], v);
                        strLine = csv.ReadLine();
                    }
                    csv.Dispose(); fs2.Dispose();
                    GC.Collect();
                }
                #endregion

                #region Output Source Location file
                string filename = ozoneAnalysisConfiguration.analysisOptionO.scenarioName + " SSIA Source Location.csv";
                BaseOutput baseOutput = new BaseOutput();
                File.Copy(ozoneAnalysisConfiguration.modelInputO.SourceCoordinateFile, _resultFilePath + "\\" + filename, true);
                baseOutput.outputName = filename.Replace(".csv", "");
                baseOutput.outputType = "Source Location";
                baseOutput.outputFilePath = _resultFilePath + "\\" + filename;
                if (File.Exists(baseOutput.outputFilePath))
                {
                    FileInfo fileInfo = new FileInfo(baseOutput.outputFilePath);
                    baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                }
                else
                {
                    baseOutput.outputSize = 0;
                }
                baseScenario.lstOutput.Add(baseOutput);

                CalculateDistance(ref dicCells, dicSource);

                #endregion
                #endregion


                if (!ozoneAnalysisConfiguration.analysisOptionO.useModelFRMData)
                {
                    SaveSSIAOzoneData(baseScenario, dicOzoneDataOutput, false, false,dicCells,null);
                    return true;
                }
                #region change dicModelDataPM projection
                double[] dConvertArrayModel = null;
                List<double> lstConvertArrayModel = new List<double>();
                List<string> lstKeyModel = dicOzoneDataOutput.Keys.ToList();
                for (int iLstKey = 0; iLstKey < dicOzoneDataOutput.Keys.Count; iLstKey++)
                {
                    lstConvertArrayModel.Add(dicOzoneDataOutput[lstKeyModel[iLstKey]].longitude);
                    lstConvertArrayModel.Add(dicOzoneDataOutput[lstKeyModel[iLstKey]].lat);
                }
                dConvertArrayModel = lstConvertArrayModel.ToArray();
                DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArrayModel, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984,
                   DotSpatial.Projections.ProjectionInfo.FromProj4String(CommonClass.projUSACMAQ), 0, dConvertArrayModel.Length / 2);
                for (int iLstKey = 0; iLstKey < dicOzoneDataOutput.Keys.Count; iLstKey++)
                {
                    dicOzoneDataOutput[lstKeyModel[iLstKey]].longitudeLamber = dConvertArrayModel[2 * iLstKey] / 100.00;
                    dicOzoneDataOutput[lstKeyModel[iLstKey]].latitudeLamber = dConvertArrayModel[2 * iLstKey + 1] / 100.00;
                }
                #endregion

                #region Read Monitor from csv
                string sFirstLine = "";
                _beginTime = DateTime.Now;
                CommonClass.CurrentLog = "Read monitor data \"" + Path.GetFileName(ozoneAnalysisConfiguration.monitorInputO.ozoneMonitorDataFile) + "\".";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                bool errorOccur = false;
                DataTable dtMonitor = CommonClass.getDataSetFromCSVAndFirstLine(ozoneAnalysisConfiguration.monitorInputO.ozoneMonitorDataFile, ref sFirstLine, ref errorOccur);
                if (dtMonitor == null || errorOccur)
                {
                    CommonClass.CurrentLog = "Fail to read monitor data \"" + Path.GetFileName(ozoneAnalysisConfiguration.monitorInputO.ozoneMonitorDataFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    return false;
                }
                //if (errorOccur)
                //{
                //    CommonClass.CurrentLog = "There are errors in the monitor file of " + ozoneAnalysisConfiguration.monitorInputO.ozoneMonitorDataFile + ". The error rows were removed.";
                //    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                //}
                string startYear = ozoneAnalysisConfiguration.monitorInputO.ozoneStartYear.Split('-')[1];
                string endYear = ozoneAnalysisConfiguration.monitorInputO.ozoneEndYear.Split('-')[1];
                List<string> lstMonitorYear = new List<string>();
                for (int i = Convert.ToInt16(startYear); i <= Convert.ToInt16(endYear); i++)
                {
                    lstMonitorYear.Add(i.ToString());
                }
                Dictionary<string, SSIAOzoneMonitor> dicOzoneMonitor = new Dictionary<string, SSIAOzoneMonitor>();
                //-------首先得到各个字段的index-------
                iID = -1; iType = -1; iLat = -1; iLong = -1; int iPOC = -1; int iDVYear = -1; iO3 = -1; int iStateName = -1; int iCountyName = -1;
                try
                {
                    for (int i = 0; i < dtMonitor.Columns.Count; i++)
                    {
                        DataColumn dc = dtMonitor.Columns[i];
                        switch (dc.ColumnName.ToLower().Trim())
                        {
                            case "_id":
                                iID = i;
                                break;
                            case "_type":
                                iType = i;
                                break;
                            case "lat":
                                iLat = i;
                                break;
                            case "long":
                                iLong = i;
                                break;
                            case "poc":
                                iPOC = i;
                                break;
                            case "dvyear":
                                iDVYear = i;
                                break;
                            case "_state_name":
                                iStateName = i;
                                break;
                            case "_county_name":
                                iCountyName = i;
                                break;
                            case "o3":
                                iO3 = i;
                                break;
                        }
                    }
                    //bool isOK = true;
                    foreach (DataRow dr in dtMonitor.Rows)
                    {
                        //try
                        //{
                        //----------解析Monitor 首先去掉=-9的值，然后根据StartYear 求出 StartYear,StartYear+1,StartYear+2的均值*10 -> int /10 最后仍然是int 值。如果都没有Ozone="."
                        //if ((dr[iDVYear].ToString() == ozoneAnalysisConfiguration.filteringInterpolationO.endYear.Substring(0,4) ||
                        //    dr[iDVYear].ToString() == (Convert.ToInt32(ozoneAnalysisConfiguration.filteringInterpolationO.endYear.Substring(0, 4)) + 1).ToString() ||
                        //    dr[iDVYear].ToString() == (Convert.ToInt32(ozoneAnalysisConfiguration.filteringInterpolationO.endYear.Substring(0, 4)) + 2).ToString()))
                        //{
                        if (dicOzoneMonitor.ContainsKey(dr[iID].ToString()))
                        {
                            dicOzoneMonitor[dr[iID].ToString()].dicOzone.Add(dr[iDVYear].ToString(), Convert.ToDouble(dr[iO3]));

                        }
                        else
                        {
                            dicOzoneMonitor.Add(dr[iID].ToString(), new SSIAOzoneMonitor());
                            dicOzoneMonitor[dr[iID].ToString()].dicOzone = new Dictionary<string, double>();
                            dicOzoneMonitor[dr[iID].ToString()].dicOzone.Add(dr[iDVYear].ToString(), Convert.ToDouble(dr[iO3]));
                            dicOzoneMonitor[dr[iID].ToString()].id = dr[iID].ToString();
                            dicOzoneMonitor[dr[iID].ToString()].type = dr[iType].ToString();
                            dicOzoneMonitor[dr[iID].ToString()].lat = Convert.ToDouble(dr[iLat]);
                            dicOzoneMonitor[dr[iID].ToString()].longitude = Convert.ToDouble(dr[iLong]);
                            dicOzoneMonitor[dr[iID].ToString()].county = dr[iCountyName].ToString();
                            dicOzoneMonitor[dr[iID].ToString()].state = dr[iStateName].ToString();
                        }
                        //}
                        //}
                        //catch
                        //{
                        //    isOK = false;
                        //}
                    }
                    //if (!errorOccur && !isOK)
                    //{
                    //    CommonClass.CurrentLog = "Skip some abnormal data.";
                    //    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    //}
                }
                catch
                {
                    CommonClass.CurrentLog = "Fail to read monitor data \"" + Path.GetFileName(ozoneAnalysisConfiguration.monitorInputO.ozoneMonitorDataFile) + "\".";
                    CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                    return false;
                }
                dtMonitor.Dispose();
                GC.Collect();

                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentLog = "Finish reading monitor data: " + CommonClass.TotalTime + " s.";
                CommonClass.CurrentBaseScenario.log.lstLog.Add(CommonClass.CurrentLog);
                _beginTime = DateTime.Now;

                #region
                //--------------修正dicOzoneMonitor的坐标系！-------------------
                double[] dConvertArrayMonitor = null;
                List<double> lstConvertArrayMonitor = new List<double>();
                List<string> lstKeyMonitor = dicOzoneMonitor.Keys.ToList();
                for (int iLstKey = 0; iLstKey < dicOzoneMonitor.Keys.Count; iLstKey++)
                {
                    lstConvertArrayMonitor.Add(dicOzoneMonitor[lstKeyMonitor[iLstKey]].longitude);
                    lstConvertArrayMonitor.Add(dicOzoneMonitor[lstKeyMonitor[iLstKey]].lat);
                }
                dConvertArrayMonitor = lstConvertArrayMonitor.ToArray();
                DotSpatial.Projections.Reproject.ReprojectPoints(dConvertArrayMonitor, null, DotSpatial.Projections.KnownCoordinateSystems.Geographic.World.WGS1984,
                   DotSpatial.Projections.ProjectionInfo.FromProj4String(CommonClass.projUSACMAQ), 0, dConvertArrayMonitor.Length / 2);
                for (int iLstKey = 0; iLstKey < dicOzoneMonitor.Keys.Count; iLstKey++)
                {
                    dicOzoneMonitor[lstKeyMonitor[iLstKey]].longitudeLamber = dConvertArrayMonitor[2 * iLstKey] / 100.00;
                    dicOzoneMonitor[lstKeyMonitor[iLstKey]].latitudeLamber = dConvertArrayMonitor[2 * iLstKey + 1] / 100.00;
                }
                #endregion

                foreach (KeyValuePair<string, SSIAOzoneMonitor> k in dicOzoneMonitor)
                {
                    List<double> lstTemp = new List<double>();
                    foreach (KeyValuePair<string, double> kin in dicOzoneMonitor[k.Key].dicOzone)
                    {
                        if (lstMonitorYear.Contains(kin.Key))
                        //if ((kin.Key == ozoneAnalysisConfiguration.monitorInputO.ozoneEndYear.Substring(0, 4) ||
                        //kin.Key == (Convert.ToInt32(ozoneAnalysisConfiguration.monitorInputO.ozoneEndYear.Substring(0, 4)) + 1).ToString() ||
                        //kin.Key == (Convert.ToInt32(ozoneAnalysisConfiguration.monitorInputO.ozoneEndYear.Substring(0, 4)) + 2).ToString()))
                        {
                            if (kin.Value > -9)
                                lstTemp.Add(kin.Value);
                        }
                    }
                    if (lstTemp.Count > 0)
                    {
                        dicOzoneMonitor[k.Key].ozone = Math.Round(lstTemp.Average(), 1);
                        dicOzoneMonitor[k.Key].datacount = lstTemp.Count;
                    }
                    else
                        dicOzoneMonitor[k.Key].ozone = -7;
                }
                //_endTime = DateTime.Now;
                //CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                //CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish reading monitor data: " + CommonClass.TotalTime + " s.");
                //CommonClass.CurrentLog = "Finish reading monitor data: " + CommonClass.TotalTime + " s.";
                #endregion

                #region Get Point Value And Save
                _beginTime = DateTime.Now;
                //---------根据是否3*3 1*1得到Point等的值
                //--------------首先得到monitor属于哪个网格-------简单的方法可以判断以最近的点作为它的网格。首先可以求出第一个网格的大小，在小于一倍网格宽度和长度的最大值求最近点
                Dictionary<string, string> dicMonitorInModel = new Dictionary<string, string>();
                double dFirst = dicOzoneDataOutput.First().Value.longitude, dLen = 0, dLat = 0;
                int iFirst = Convert.ToInt32(dicOzoneDataOutput.First().Key);

                if (dicOzoneDataOutput.ContainsKey((((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()))
                {

                    dLen = Math.Abs(dicOzoneDataOutput[(((iFirst / 1000) + 1) * 1000 + iFirst % 1000).ToString()].longitude -
                        dicOzoneDataOutput.First().Value.longitude
                        );
                    dLat = Math.Abs(dicOzoneDataOutput[(((iFirst / 1000)) * 1000 + iFirst % 1000 + 1).ToString()].lat -
                        dicOzoneDataOutput.First().Value.lat
                        );
                    dLen *= 2; dLat *= 2;

                }
                //----------修正算法 首先计算出所有的左上角和右下角以及Model中心点的对应关系--------
                Dictionary<string, Extent> dicExtentForModel = new Dictionary<string, Extent>();
                foreach (KeyValuePair<string, SSIAOzoneData> k in dicOzoneDataOutput)
                {
                    try
                    {
                        int Col = Convert.ToInt32(k.Key) / 1000;
                        int Row = Convert.ToInt32(k.Key) % 1000;
                        //------如果没有上格，则使用下格
                        SSIAOzoneData ozoneModelTop = null, ozoneModelLeft = null;
                        if (dicOzoneDataOutput.ContainsKey(((Col - 1) * 1000 + Row).ToString()))
                        {
                            ozoneModelLeft = dicOzoneDataOutput[((Col - 1) * 1000 + Row).ToString()];
                        }
                        else if (dicOzoneDataOutput.ContainsKey(((Col + 1) * 1000 + Row).ToString()))
                        {
                            ozoneModelLeft = dicOzoneDataOutput[((Col + 1) * 1000 + Row).ToString()];
                        }
                        if (dicOzoneDataOutput.ContainsKey((Col * 1000 + Row + 1).ToString()))
                        {
                            ozoneModelTop = dicOzoneDataOutput[(Col * 1000 + Row + 1).ToString()];
                        }
                        else if (dicOzoneDataOutput.ContainsKey((Col * 1000 + Row - 1).ToString()))
                        {
                            ozoneModelTop = dicOzoneDataOutput[(Col * 1000 + Row - 1).ToString()];
                        }
                        if (ozoneModelLeft != null && ozoneModelTop != null)
                        {
                            dicExtentForModel.Add(k.Key, new Extent(k.Value.longitude - Math.Abs(ozoneModelTop.longitude - ozoneModelLeft.longitude) / 2.00,
                                k.Value.lat - Math.Abs(ozoneModelLeft.lat - ozoneModelTop.lat) / 2.00, k.Value.longitude + Math.Abs(ozoneModelTop.longitude - ozoneModelLeft.longitude) / 2.00,
                                k.Value.lat + Math.Abs(ozoneModelLeft.lat - ozoneModelTop.lat) / 2.00));

                        }
                    }
                    catch
                    {
                    }

                }
                //---------计算两个网格之内；然后属于哪个的网格
                foreach (KeyValuePair<string, SSIAOzoneMonitor> k in dicOzoneMonitor)
                {
                    try
                    {
                        var query = dicOzoneDataOutput.Where(p => Math.Abs(p.Value.longitude - k.Value.longitude) < dLen && Math.Abs(p.Value.lat - k.Value.lat) < dLat).ToList();
                        string sModelIDTemp = "";
                        if (query.Count() > 0)
                        {
                            DotSpatial.Topology.Coordinate coor = new DotSpatial.Topology.Coordinate(k.Value.longitude, k.Value.lat);
                            if (sModelIDTemp == "")
                            {
                                sModelIDTemp = query.OrderBy(p => CommonClass.getDistanceFrom2Point(p.Value.longitude, p.Value.lat, k.Value.longitude, k.Value.lat)).First().Key;
                                dicMonitorInModel.Add(k.Key, sModelIDTemp);
                                k.Value.gridcell = sModelIDTemp;
                            }
                        }
                    }
                    catch
                    {
                    }
                }
                foreach (KeyValuePair<string, SSIAOzoneMonitor> k in dicOzoneMonitor)
                {
                    if (!dicMonitorInModel.ContainsKey(k.Key)) continue;
                    int Col = Convert.ToInt32(dicMonitorInModel[k.Key]) / 1000;
                    int Row = Convert.ToInt32(dicMonitorInModel[k.Key]) % 1000;
                    List<string> lstSurround = new List<string>();
                    switch (ozoneAnalysisConfiguration.monitorInputO.temporalAdjustmentAtMonitorGrid)
                    {
                        case "1x1":
                            lstSurround.Add(dicMonitorInModel[k.Key]);
                            break;
                        case "3x3":
                            for (int i3 = -1; i3 <= 1; i3++)
                            {
                                for (int j3 = -1; j3 <= 1; j3++)
                                {
                                    lstSurround.Add(((Col + i3) * 1000 + (Row + j3)).ToString());
                                }

                            }
                            break;
                        case "5x5":
                            for (int i5 = -2; i5 <= 2; i5++)
                            {
                                for (int j5 = -2; j5 <= 2; j5++)
                                {
                                    lstSurround.Add(((Col + i5) * 1000 + (Row + j5)).ToString());
                                }

                            }
                            break;
                        case "7x7":
                            for (int i7 = -3; i7 <= 3; i7++)
                            {
                                for (int j7 = -3; j7 <= 3; j7++)
                                {
                                    lstSurround.Add(((Col + i7) * 1000 + (Row + j7)).ToString());
                                }

                            }
                            break;

                    }
                    var query = dicOzoneDataOutput.Where(p => lstSurround.Contains(p.Key)).ToList();
                    int iQueryCount = query.Count;
                    switch (ozoneAnalysisConfiguration.monitorInputO.temporalAdjustmentType)
                    {
                        case "Mean":
                            if (query.Count() > 0)
                            {
                                List<double> lstbaseO3 = new List<double>();
                                List<double> lstaltO3 = new List<double>();
                                for (int i = 0; i < query.Count(); i++)
                                {
                                    KeyValuePair<string, SSIAOzoneData> kin = query.ToArray()[i];
                                    if (kin.Value.baseOzone > 0)
                                        lstbaseO3.Add(kin.Value.baseOzone);
                                    if (kin.Value.altOzone > 0)
                                        lstaltO3.Add(kin.Value.altOzone);
                                }
                                if (lstbaseO3.Count > 0 && lstaltO3.Count > 0 && k.Value.ozone > 0)
                                {
                                    //k.Value.altozone = k.Value.ozone * (lstaltO3.Average() / lstbaseO3.Average());
                                    //k.Value.deltaozone = k.Value.altozone - k.Value.ozone;
                                    k.Value.deltaozone = lstaltO3.Average() - lstbaseO3.Average();
                                    k.Value.altozone = k.Value.ozone + k.Value.deltaozone;
                                }
                                else
                                {
                                    k.Value.altozone = -9;
                                    k.Value.deltaozone = 0;
                                }
                            }
                            break;
                        case "Maximum":
                            if (query.Count() > 0)
                            {
                                List<double> lstbaseO3 = new List<double>();
                                List<double> lstaltO3 = new List<double>();
                                for (int i = 0; i < query.Count(); i++)
                                {
                                    KeyValuePair<string, SSIAOzoneData> kin = query.ToArray()[i];
                                    if (kin.Value.baseOzone > 0)
                                        lstbaseO3.Add(kin.Value.baseOzone);
                                    if (kin.Value.altOzone > 0)
                                        lstaltO3.Add(kin.Value.altOzone);
                                }
                                if (lstbaseO3.Count > 0 && lstaltO3.Count > 0 && k.Value.ozone > 0)
                                {
                                    //k.Value.altozone = k.Value.ozone * (lstaltO3.Max() / lstbaseO3.Max());
                                    //k.Value.deltaozone = k.Value.altozone - k.Value.ozone;
                                    k.Value.deltaozone = lstaltO3.Max() - lstbaseO3.Max();
                                    k.Value.altozone = k.Value.ozone + k.Value.deltaozone;
                                }
                                else
                                {
                                    k.Value.altozone = -9;
                                    k.Value.deltaozone = 0;
                                }
                            }
                            break;
                        case "Maximum-paired in space":
                            if (query.Count() > 0)
                            {
                                double baseO3 = 0;
                                double altO3 = 0;
                                //string id = "";//for test
                                List<double> lstaltO3 = new List<double>();
                                for (int i = 0; i < query.Count(); i++)
                                {
                                    KeyValuePair<string, SSIAOzoneData> kin = query.ToArray()[i];
                                    if (kin.Value.baseOzone > baseO3)
                                    {
                                        baseO3 = kin.Value.baseOzone;
                                        altO3 = kin.Value.altOzone;
                                        //id = kin.Key;//for test
                                    }
                                }

                                //for test
                                //double b = query.Select(q => q.Value.baseOzone).ToList().Max() - baseO3;
                                //double a = query.Select(q => q.Value.altOzone).ToList().Max() - altO3;
                                //if (query.ToDictionary(q => q.Key, q => q.Value)[id].baseOzone != baseO3 || query.ToDictionary(q => q.Key, q => q.Value)[id].baseOzone != baseO3)
                                //{ }

                                if (baseO3 > 0 && altO3 > 0 && k.Value.ozone > 0)
                                {
                                    k.Value.deltaozone = altO3 - baseO3;
                                    k.Value.altozone = k.Value.ozone + k.Value.deltaozone;
                                }
                                else
                                {
                                    k.Value.altozone = -9;
                                    k.Value.deltaozone = 0;
                                }
                            }
                            break;
                    }
                    //------------得到Max Delta
                    k.Value.deltaozone = query.Max(p => p.Value.deltaOzone);
                    if (k.Value.deltaozone < 0) k.Value.deltaozone = 0;
                }
                Dictionary<string, SSIAOzoneMonitor> dicMonitor = dicOzoneMonitor.Where(p => dicMonitorInModel.ContainsKey(p.Key)).ToDictionary(p => p.Key, p => p.Value);
                SaveSSIAOzonePoint(CommonClass.CurrentBaseScenario, dicMonitor);
                dicMonitor.Clear();
                GC.Collect();
                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish computing point: " + CommonClass.TotalTime + " s.");
                CommonClass.CurrentLog = "Finish computing point: " + CommonClass.TotalTime + " s.";
                #endregion

                #region VNA
                _beginTime = DateTime.Now;
                //-------------如果需要VNA求VNA------------------------------------------------
                //-----------得到Neighbor --VNA---------
                Dictionary<string, SSIAOzoneMonitor> dicOzoneMonitorLatLong = new Dictionary<string, SSIAOzoneMonitor>();
                double iMinLong = 180, iMinLat = 180, iMaxLong = -180, iMaxLat = -180, dLong10 = 1, dLat10 = 1;
                foreach (KeyValuePair<string, SSIAOzoneMonitor> k in dicOzoneMonitor)
                {
                    if (dicOzoneMonitor.ContainsKey(k.Key) && !dicOzoneMonitorLatLong.ContainsKey(k.Value.longitudeLamber + "," + k.Value.latitudeLamber))
                    {
                        if (dicOzoneMonitor[k.Key].ozone > 0)
                        {
                            dicOzoneMonitorLatLong.Add(k.Value.longitudeLamber + "," + k.Value.latitudeLamber, k.Value);
                            if (k.Value.longitude > iMaxLong) iMaxLong = k.Value.longitude;
                            if (k.Value.lat > iMaxLat) iMaxLat = k.Value.lat;
                            if (k.Value.longitude < iMinLong) iMinLong = k.Value.longitude;
                            if (k.Value.lat < iMinLat) iMinLat = k.Value.lat;
                        }
                    }
                }

                dLong10 = (iMaxLong - iMinLong) / 10.00;
                dLat10 = (iMaxLat - iMinLat) / 10.00;
                foreach (KeyValuePair<string, SSIAOzoneData> k in dicOzoneDataOutput)
                {
                    List<double> fsInter = new List<double>();
                    fsInter.Add(k.Value.longitudeLamber);
                    fsInter.Add(k.Value.latitudeLamber);
                    //VNA简化算法求半径范围内的监测点做VNA ，一开始以5个经纬度来算一直达到10个为止
                    Dictionary<string, double> dicDistanceMonitor = new Dictionary<string, double>();

                    foreach (KeyValuePair<string, SSIAOzoneMonitor> kin in dicOzoneMonitorLatLong)
                    {
                        if (dicMonitorInModel.ContainsKey(kin.Value.id))
                        {
                            dicDistanceMonitor.Add(kin.Value.id, (k.Value.longitude - kin.Value.longitude) * (k.Value.longitude - kin.Value.longitude) + (k.Value.lat - kin.Value.lat) * (k.Value.lat - kin.Value.lat));
                        }
                    }
                    List<KeyValuePair<string, double>> query = new List<KeyValuePair<string, double>>();
                    bool isSame = false;
                    if (dicOzoneMonitorLatLong.ContainsKey(k.Value.longitudeLamber + "," + k.Value.latitudeLamber)) isSame = true;
                    if (!isSame)
                    {
                        if (Math.Abs(k.Value.longitude - iMinLong) < dLong10 || Math.Abs(iMaxLong - k.Value.longitude) < dLong10
                            || Math.Abs(k.Value.lat - iMinLat) < dLat10 || Math.Abs(iMaxLat - k.Value.lat) < dLat10)
                        {
                            query = dicDistanceMonitor.Where(p => p.Value < 484).ToList();
                        }
                        else
                        {
                            query = dicDistanceMonitor.Where(p => p.Value < 64).ToList();//.OrderBy(p=>p.Value).ToList().GetRange(0,idicMonitorValues).ToDictionary(p=>p.Key,p=>p.Value);// .Where(p => lstDouble.GetRange(0, idicMonitorValues).Contains(p.Value));
                            int iDistanceForQuery = 1;
                            while (query.Count < 20 && query.Count < dicDistanceMonitor.Count)
                            {
                                query = dicDistanceMonitor.Where(p => p.Value < 64 + iDistanceForQuery).ToList();
                                iDistanceForQuery++;

                            }
                        }

                        foreach (KeyValuePair<string, double> kin in query)
                        {
                            if (dicOzoneMonitor.ContainsKey(kin.Key))
                            {
                                fsInter.Add(dicOzoneMonitor[kin.Key].longitudeLamber);
                                fsInter.Add(dicOzoneMonitor[kin.Key].latitudeLamber);

                            }
                        }
                    }
                    //----------------end VNA简化算法
                    double vnaSum = 0, evnaSum = 0, distanceSum = 0, distance = 0, distanceSumEvna = 0;
                    double vna = 0, evna = 0;
                    List<double> fsout = new List<double>();
                    if (!isSame)
                        CommonClass.VoronoiPoints(fsInter.ToArray(), ref fsout);//
                    else
                    {
                        fsout.Add(k.Value.longitudeLamber);
                        fsout.Add(k.Value.latitudeLamber);
                    }
                    //----------------根据得到的邻居计算数值----------------
                    List<string> fsoutString = new List<string>();
                    for (int ifsout = 0; ifsout < fsout.Count; ifsout++)
                    {
                        if (ifsout % 2 == 1)
                        {
                            fsoutString.Add(fsout[ifsout - 1] + "," + fsout[ifsout]);
                        }
                    }
                    //-------------------------------------------------------------
                    if (fsoutString.Count == 0) continue;

                    //default-Inverse Distance Weights
                    foreach (string s in fsoutString)
                    {
                        double d = CommonClass.getDistanceFrom2Point(k.Value.longitude, k.Value.lat, dicOzoneMonitorLatLong[s].longitude, dicOzoneMonitorLatLong[s].lat);
                        distance = d == 0 ? 1 : 1.0000 / d;
                        distanceSum += distance;
                        if (dicOzoneMonitorLatLong[s].ozone < 0)
                        { }
                        vnaSum += dicOzoneMonitorLatLong[s].ozone * distance;
                        try
                        {
                            evnaSum += dicOzoneMonitorLatLong[s].ozone * distance * k.Value.srf / dicOzoneDataOutput[dicMonitorInModel[dicOzoneMonitorLatLong[s].id]].srf;
                            distanceSumEvna += distance;
                        }
                        catch
                        {
                        }
                    }
                    try
                    {
                        if (vnaSum < 0 || Double.IsNaN(vnaSum) || distanceSum == 0)
                            vna = -13;
                        else
                            vna = Math.Round(vnaSum / distanceSum, 7);
                        if (evnaSum < 0 || Double.IsNaN(evnaSum) || distanceSumEvna == 0)
                            evna = -8;
                        else
                            evna = Math.Round(evnaSum / distanceSumEvna, 7);
                    }
                    catch
                    {
                    }

                    k.Value.CIAvna = vna;// +k.Value.deltaOzone;
                    k.Value.CIAevna = evna;// +k.Value.deltaOzone;
                    #region
                    #endregion
                }
                _endTime = DateTime.Now;
                CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish interpolating spatial field: " + CommonClass.TotalTime + " s.");
                CommonClass.CurrentLog = "Finish interpolating spatial field: " + CommonClass.TotalTime + " s.";
                GC.Collect();
                GC.Collect();

                #endregion

                #region Downscaler begins here by Yangwenwei
                List<DownscaleR.Ozone.OzoneModel> lstDSresult = new List<DownscaleR.Ozone.OzoneModel>();
                if (ozoneAnalysisConfiguration.monitorInputO.useDownscaler)
                {
                    _beginTime = DateTime.Now;
                    //monitor
                    string[] lstMonitorID4DS = dicOzoneMonitor.Select(p => p.Value.id).ToArray();
                    double[] lstMonitorLat4DS = dicOzoneMonitor.Select(p => p.Value.lat).ToArray();
                    double[] lstMonitorLongl4DS = dicOzoneMonitor.Select(p => p.Value.longitude).ToArray();
                    double[] lstMonitor4DS = dicOzoneMonitor.Select(p => p.Value.ozone).ToArray();
                    Tuple<string[], double[], double[], double[]> _tupleMonitor4DS = new Tuple<string[], double[], double[], double[]>(
                        lstMonitorID4DS,
                        lstMonitorLat4DS,
                        lstMonitorLongl4DS,
                        lstMonitor4DS
                        );
                    #region output monitor
                    //SaveDSMonitorData(dicOzoneMonitor);
                    #endregion

                    //model
                    string[] lstModelID4DS = dicOzoneDataOutput.Select(p => p.Value.id).ToArray();
                    double[] lstModelLat4DS = dicOzoneDataOutput.Select(p => p.Value.lat).ToArray();
                    double[] lstModelLong4DS = dicOzoneDataOutput.Select(p => p.Value.longitude).ToArray();
                    double[] lstModel4DS = dicOzoneDataOutput.Select(p => Convert.ToDouble(p.Value.baseOzone)).ToArray();
                    Tuple<string[], double[], double[], double[]> _tupleModel4DS = new Tuple<string[], double[], double[], double[]>(
                        lstModelID4DS,
                        lstModelLat4DS,
                        lstModelLong4DS,
                        lstModel4DS
                        );
                    #region output model
                    //SaveDSModelData(dicOzoneDataOutput);
                    #endregion

                    DownscaleR.CommonSettings common = new DownscaleR.CommonSettings();
                    common.Burn = ozoneAnalysisConfiguration.monitorInputO.DSBurn;
                    common.Cmaqres = ozoneAnalysisConfiguration.monitorInputO.DSCmaqres;
                    common.Thin = ozoneAnalysisConfiguration.monitorInputO.DSThin;
                    common.Numit = ozoneAnalysisConfiguration.monitorInputO.DSNumit;
                    DownscaleR.Ozone.OzoneAnalysis analysis = new DownscaleR.Ozone.OzoneAnalysis(common, _tupleMonitor4DS, _tupleModel4DS);
                    analysis.Start();
                    lstDSresult = analysis.ResultOutputData;

                    _endTime = DateTime.Now;
                    CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                    CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish downscalser method: " + CommonClass.TotalTime + " s.");
                    CommonClass.CurrentLog = "Finish downscalser method: " + CommonClass.TotalTime + " s.";
                }

                #endregion

                //_endTime = DateTime.Now;
                //CommonClass.TotalTime = Math.Round(_endTime.Subtract(_beginTime).TotalSeconds, 3);
                //CommonClass.CurrentBaseScenario.log.lstLog.Add("Finish interpolating spatial field: " + CommonClass.TotalTime + " s.");
                //CommonClass.CurrentLog = "Finish interpolating spatial field: " + CommonClass.TotalTime + " s.";
                SaveSSIAOzoneData(baseScenario, dicOzoneDataOutput, ozoneAnalysisConfiguration.monitorInputO.useVNA, ozoneAnalysisConfiguration.monitorInputO.useEVNA, dicCells, lstDSresult);
                baseScenario.lstOutput.Reverse();// point file below data file
                #region baseScenario.lstOutput sorted by ty
                /*var scenarioName = ozoneAnalysisConfiguration.analysisOptionO.scenarioName;
                BaseOutput bo;
                List<BaseOutput> lstNew = new List<BaseOutput>();
                bo = baseScenario.lstOutput.FirstOrDefault(_ => _.outputName.Substring(scenarioName.Length, _.outputName.Length - scenarioName.Length).Contains("SSIA Source Location"));
                if (bo != null) lstNew.Add(bo);
                bo = baseScenario.lstOutput.FirstOrDefault(_ => _.outputName.Substring(scenarioName.Length, _.outputName.Length - scenarioName.Length).Contains("SSIA Ozone Data"));
                if (bo != null) lstNew.Add(bo);
                bo = baseScenario.lstOutput.FirstOrDefault(_ => _.outputName.Substring(scenarioName.Length, _.outputName.Length - scenarioName.Length).Contains("SSIA Ozone Point"));
                if (bo != null) lstNew.Add(bo);
                baseScenario.lstOutput = lstNew;*/
                #endregion
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool SaveSSIAOzoneData(BaseScenario baseScenario, Dictionary<string, SSIAOzoneData> dicData, bool outputCIAvna, bool outputCIAevna, Dictionary<string, double[]> dicDistanceFromSource, List<DownscaleR.Ozone.OzoneModel> lstDSresult)
        {
            if (!(baseScenario.configuration is SSIAOzoneAnalysisConfiguration))
            {
                return false;
            }
            try
            {
                int decimaldigits = 8;
                SSIAOzoneAnalysisConfiguration ozoneAnalysisConfiguration = baseScenario.configuration as SSIAOzoneAnalysisConfiguration;
                DataTable dt = new DataTable();
                DataRow dr = null;
                dt.Columns.Add("_id");
                dt.Columns.Add("lat");
                dt.Columns.Add("long");
                dt.Columns.Add("Base_O3");
                dt.Columns.Add("Alt_O3");
                dt.Columns.Add("DeltaO3 (Max)");//DeltaC(SIA)
                if (outputCIAevna)
                {
                    dt.Columns.Add("O3 (BG_eVNA)");//C(CIA_eVNA)
                    dt.Columns.Add("Alt_O3 (BG_eVNA)");
                }
                if (outputCIAvna)
                {
                    dt.Columns.Add("O3 (BG_VNA)");//C(CIA_VNA)
                    dt.Columns.Add("Alt_O3 (BG_VNA)");
                }
                if (ozoneAnalysisConfiguration.monitorInputO.useDownscaler)
                {
                    dt.Columns.Add("O3 (BG_Downscaler)");
                    dt.Columns.Add("Alt_O3 (BG_Downscaler)");
                    //dt.Columns.Add("DS_SEpred (BG_DS)");
                }
                dt.Columns.Add("Cell center distance from source(km)");
                         
                int j = 0;
                foreach (KeyValuePair<string, SSIAOzoneData> k in dicData)
                {
                    int i = 0;
                    dr = dt.NewRow();
                    dr[i++] = k.Value.id;
                    dr[i++] = Math.Round(k.Value.lat, 6);
                    dr[i++] = Math.Round(k.Value.longitude, 6);
                    dr[i++] = Math.Round(k.Value.baseOzone, decimaldigits);
                    dr[i++] = Math.Round(k.Value.altOzone, decimaldigits);
                    dr[i++] = Math.Round(k.Value.deltaOzone, decimaldigits);
                    if (outputCIAevna)
                    {
                        dr[i++] = Math.Round(k.Value.CIAevna, decimaldigits);
                        dr[i++] = Math.Round(k.Value.CIAevna + k.Value.deltaOzone, decimaldigits);
                    }
                    if (outputCIAvna)
                    {
                        dr[i++] = Math.Round(k.Value.CIAvna, decimaldigits);
                        dr[i++] = Math.Round(k.Value.CIAvna + k.Value.deltaOzone, decimaldigits);
                    }
                    if (ozoneAnalysisConfiguration.monitorInputO.useDownscaler)
                    {
                        dr[i++] = Math.Round(lstDSresult[j].DS_Prediction, decimaldigits);
                        dr[i++] = Math.Round(lstDSresult[j].DS_Prediction + k.Value.deltaOzone, decimaldigits);
                        //dr[i++] = Math.Round(lstDSresult[j].DS_SEpred, decimaldigits);
                    }
                    dr[i++] = dicDistanceFromSource[k.Value.id][2];
                    dt.Rows.Add(dr);
                    j++;
                }
                #region
                ////dicData = dicData.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
                //if (outputCIAvna && outputCIAevna)
                //{
                //    foreach (KeyValuePair<string, SSIAOzoneData> k in dicData)
                //    {
                //        dr = dt.NewRow();
                //        dr[0] = k.Value.id;
                //        dr[1] = Math.Round(k.Value.lat, 6);
                //        dr[2] = Math.Round(k.Value.longitude, 6);
                //        dr[3] = Math.Round(k.Value.baseOzone, decimaldigits);
                //        dr[4] = Math.Round(k.Value.altOzone, decimaldigits);
                //        dr[5] = Math.Round(k.Value.deltaOzone, decimaldigits);
                //        dr[6] = Math.Round(k.Value.CIAevna, decimaldigits);
                //        dr[7] = Math.Round(k.Value.CIAevna + k.Value.deltaOzone, decimaldigits);
                //        dr[8] = Math.Round(k.Value.CIAvna, decimaldigits);
                //        dr[9] = Math.Round(k.Value.CIAvna + k.Value.deltaOzone, decimaldigits);

                //        dr[10] = dicDistanceFromSource[k.Value.id][2];
                //        dt.Rows.Add(dr);
                //    }
                //}
                //else if (outputCIAvna)
                //{
                //    foreach (KeyValuePair<string, SSIAOzoneData> k in dicData)
                //    {
                //        dr = dt.NewRow();
                //        dr[0] = k.Value.id;
                //        dr[1] = Math.Round(k.Value.lat, 6);
                //        dr[2] = Math.Round(k.Value.longitude, 6);
                //        dr[3] = Math.Round(k.Value.baseOzone, decimaldigits);
                //        dr[4] = Math.Round(k.Value.altOzone, decimaldigits);
                //        dr[5] = Math.Round(k.Value.deltaOzone, decimaldigits);
                //        dr[6] = Math.Round(k.Value.CIAvna, decimaldigits);
                //        dr[7] = Math.Round(k.Value.CIAvna + k.Value.deltaOzone, decimaldigits);
                //        dr[8] = dicDistanceFromSource[k.Value.id][2];
                //        dt.Rows.Add(dr);
                //    }
                //}
                //else if (outputCIAevna)
                //{
                //    foreach (KeyValuePair<string, SSIAOzoneData> k in dicData)
                //    {
                //        dr = dt.NewRow();
                //        dr[0] = k.Value.id;
                //        dr[1] = Math.Round(k.Value.lat, 6);
                //        dr[2] = Math.Round(k.Value.longitude, 6);
                //        dr[3] = Math.Round(k.Value.baseOzone, decimaldigits);
                //        dr[4] = Math.Round(k.Value.altOzone, decimaldigits);
                //        dr[5] = Math.Round(k.Value.deltaOzone, decimaldigits);
                //        dr[6] = Math.Round(k.Value.CIAevna, decimaldigits);
                //        dr[7] = Math.Round(k.Value.CIAevna + k.Value.deltaOzone, decimaldigits);
                //        dr[8] = dicDistanceFromSource[k.Value.id][2];
                //        dt.Rows.Add(dr);
                //    }
                //}
                //else
                //{
                //    foreach (KeyValuePair<string, SSIAOzoneData> k in dicData)
                //    {
                //        dr = dt.NewRow();
                //        dr[0] = k.Value.id;
                //        dr[1] = Math.Round(k.Value.lat, 6);
                //        dr[2] = Math.Round(k.Value.longitude, 6);
                //        dr[3] = Math.Round(k.Value.baseOzone, decimaldigits);
                //        dr[4] = Math.Round(k.Value.altOzone, decimaldigits);
                //        dr[5] = Math.Round(k.Value.deltaOzone, decimaldigits);
                //        dr[6] = dicDistanceFromSource[k.Value.id][2];
                //        dt.Rows.Add(dr);
                //    }
                //}
                #endregion
                if (!CommonClass.IsBatch)
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName;
                }
                else
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName;
                }
                if (!Directory.Exists(_resultFilePath))
                    System.IO.Directory.CreateDirectory(_resultFilePath);
                //modify file name
                string strFile = ozoneAnalysisConfiguration.analysisOptionO.scenarioName + " SSIA Ozone Data.csv";
                BaseOutput baseOutput = new BaseOutput();
                CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Annual");
                baseOutput.outputName = strFile.Replace(".csv", "");
                baseOutput.outputType = "Monitor Network";
                baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                if (File.Exists(_resultFilePath + @"\" + strFile))
                {
                    FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                    baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                }
                else
                {
                    baseOutput.outputSize = 0;
                }
                baseScenario.lstOutput.Add(baseOutput);
                dt.Dispose();
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }
        public static bool SaveSSIAOzonePoint(BaseScenario baseScenario, Dictionary<string, SSIAOzoneMonitor> dicOzonePoint)
        {
            if (!(baseScenario.configuration is SSIAOzoneAnalysisConfiguration))
                return false;
            try
            {
                int decimaldigits = 8;
                SSIAOzoneAnalysisConfiguration ozoneAnalysisConfiguration = baseScenario.configuration as SSIAOzoneAnalysisConfiguration;
                DataTable dt = new DataTable();
                dt.Columns.Add("_id");
                dt.Columns.Add("_type");
                dt.Columns.Add("_STATE_NAME");
                dt.Columns.Add("_COUNTY_NAME");
                dt.Columns.Add("monitor_lat");
                dt.Columns.Add("monitor_long");
                dt.Columns.Add("monitor_gridcell");
                dt.Columns.Add("O3 (Obs)");//Base_O3
                dt.Columns.Add("Alt_O3");
                dt.Columns.Add("DeltaO3(Max)");//DeltaC(Alt-Base)
                dicOzonePoint = dicOzonePoint.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
                foreach (KeyValuePair<string, SSIAOzoneMonitor> k in dicOzonePoint)
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = k.Value.id;
                    dr[1] = k.Value.type;
                    dr[2] = k.Value.state;
                    dr[3] = k.Value.county;
                    dr[4] = Math.Round(k.Value.lat, 6);
                    dr[5] = Math.Round(k.Value.longitude, 6);
                    dr[6] = k.Value.gridcell;
                    dr[7] = CommonClass.ToFixed(k.Value.ozone, decimaldigits);
                    dr[8] = CommonClass.ToFixed(k.Value.altozone, decimaldigits);
                    dr[9] = CommonClass.ToFixed(k.Value.deltaozone, decimaldigits);
                    dt.Rows.Add(dr);
                }
                if (!CommonClass.IsBatch)
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\Result\Output\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName;
                }
                else
                {
                    if (_resultFilePath == "" && _resultFilePath.Length == 0 || _resultFilePath != CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName)
                        _resultFilePath = CommonClass.ResultFilePath + @"\" + (CommonClass.CurrentBaseScenario.configuration as SSIAOzoneAnalysisConfiguration).analysisOptionO.scenarioName;
                }
                if (!Directory.Exists(_resultFilePath))
                    System.IO.Directory.CreateDirectory(_resultFilePath);

                //修正文件名称
                string strFile = ozoneAnalysisConfiguration.analysisOptionO.scenarioName + " SSIA Ozone Point.csv";
                BaseOutput baseOutput = new BaseOutput();
                CommonClass.SaveCSV(dt, _resultFilePath + @"\" + strFile, "Year");
                baseOutput.outputName = strFile.Replace(".csv", "");
                baseOutput.outputType = "Monitor Network";
                baseOutput.outputFilePath = _resultFilePath + @"\" + strFile;
                if (File.Exists(_resultFilePath + @"\" + strFile))
                {
                    FileInfo fileInfo = new FileInfo(_resultFilePath + @"\" + strFile);
                    baseOutput.outputSize = Convert.ToInt32(fileInfo.Length / 1024);
                }
                else
                {
                    baseOutput.outputSize = 0;
                }
                baseScenario.lstOutput.Add(baseOutput);
                dt.Dispose();
                GC.Collect();
                return true;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return false;
            }
        }

        public static void getAvgandSrfOfOzoneModel(SSIAOzoneData ozoneModel, SSIAOzoneAnalysisConfiguration ozoneAnalysisConfiguration)
        {
            try
            {
                double startPercentage = Convert.ToDouble(ozoneAnalysisConfiguration.calculationOption.startPercentage) * 0.01;
                double endPercentage = Convert.ToDouble(ozoneAnalysisConfiguration.calculationOption.endPercentage) * 0.01;
                List<float[]> lst = ozoneModel.lstOzone.Where(q => q.Value[0] >= 0).Select(q => q.Value).OrderBy(q => q[0]).ToList();//remove -9 
                //ozoneModel.lstOzone = ozoneModel.lstOzone.OrderBy(q => q.Value[0]).ToDictionary(q => q.Key, q => q.Value);
                int startCount = Convert.ToInt32(Math.Floor((lst.Count - 1) * startPercentage));//then select 95-98
                int endCount = Convert.ToInt32(Math.Ceiling((lst.Count - 1) * endPercentage));//
                ozoneModel.baseOzone = lst.Select(q => q[0]).ToList().GetRange(startCount, endCount - startCount + 1).Average();
                ozoneModel.altOzone = lst.Select(q => q[1]).ToList().GetRange(startCount, endCount - startCount + 1).Average();
                
                //if (ozoneModel.lstOzone.Where(p => p.Value[0] > 0).Count() > 0)
                //    ozoneModel.baseOzone = ozoneModel.lstOzone.Where(p => p.Value[0] > 0).Select(p => p.Value[0]).ToList().Average();
                //else
                //    ozoneModel.baseOzone = -9;
                //if (ozoneModel.lstOzone.Where(p => p.Value[1] > 0).Count() > 0)
                //    ozoneModel.altOzone = ozoneModel.lstOzone.Where(p => p.Value[1] > 0).Select(p => p.Value[1]).ToList().Average();
                //else
                //    ozoneModel.altOzone = -9;
                if(ozoneModel.baseOzone!=ozoneModel.altOzone)
                {

                }
                if (ozoneModel.baseOzone > 0 && ozoneModel.altOzone > 0)
                {
                    //ozoneModel.deltaOzone = lst.GetRange(startCount, endCount - startCount + 1).Max(p => p[1] - p[0]);// ozoneModel.altOzone - ozoneModel.baseOzone;
                    ozoneModel.deltaOzone = lst.Max(p => p[1] - p[0]);// ozoneModel.altOzone - ozoneModel.baseOzone;
                }
                else
                    ozoneModel.deltaOzone = 0;
                lst.Clear();
                ozoneModel.lstOzone = ozoneModel.lstOzone.OrderByDescending(p => p.Value[0]).ToDictionary(p => p.Key, p => p.Value);
                float[] values = ozoneModel.lstOzone.Values.Select(p => p[0]).ToArray();
                if (values[0] == -9 || values[0] == -7)
                {
                    ozoneModel.baseOzone = -9;
                    //ozoneModel.ppb = 70;
                    //ozoneModel.days = 0;
                    //ozoneModel.rrf = -9;
                    //if (ozoneAnalysisConfiguration.chooseDesiredOutputO.doSpatialFieldEstimates && ozoneAnalysisConfiguration.chooseDesiredOutputO.doSpatialFieldEstimatesGradAdj)
                        ozoneModel.srf = -13;
                    //else
                    //    ozoneModel.srf = -9;
                    //---------- -13?
                    return;
                }
                //------------求SRF-------根据StartDay,EndDay--------
                ozoneModel.srf = Math.Round(values.ToList().GetRange(0, 5).Average(), 1);
            }
            catch
            {
            }

        }

        [Obsolete("输出SSIA-Ozone做DS分析的监测输入数据")]
        public static void SaveDSMonitorData(Dictionary<string, SSIAOzoneMonitor> dicOzoneDataOutput)
        {
            try
            {
                if (dicOzoneDataOutput.Count <= 0)
                    return;
                FileStream fs;
                StreamWriter streamWriter;
                StringBuilder sb = new StringBuilder();
                string filename = "1monitor.csv";
                string filepath = @"D:\SMAT_InputData\SSIA_Ozone\";
                if (!Directory.Exists(filepath))
                    Directory.CreateDirectory(filepath);
                filepath += filename;
                if (File.Exists(filepath))
                    File.Delete(filepath);
                fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
                streamWriter = new StreamWriter(fs, Encoding.Default);
                sb.Append("Site,POC,Date,Lat,Lon,Conc");
                streamWriter.WriteLine(sb.ToString());
                foreach (KeyValuePair<string, SSIAOzoneMonitor> kvp in dicOzoneDataOutput)
                {
                    SSIAOzoneMonitor monitor = kvp.Value;
                    if (monitor.ozone < 0.0) continue;
                    sb.Clear();
                    sb.AppendFormat("{0},{1},{2},{3},{4},{5}", new object[] { "1", "1", "2011-1-1", monitor.lat, monitor.longitude, monitor.ozone });
                    streamWriter.WriteLine(sb.ToString());
                }
                streamWriter.Close();
                fs.Close();
                sb.Clear();
                GC.Collect();
            }
            catch
            {

            }
        }
        [Obsolete("输出SSIA-Ozone做DS分析的模型输入数据")]
        public static void SaveDSModelData(Dictionary<string, SSIAOzoneData> dicOzoneDataOutput)
        {
            try
            {
                if (dicOzoneDataOutput.Count <= 0)
                    return;
                FileStream fs;
                StreamWriter streamWriter;
                StringBuilder sb = new StringBuilder();
                string filename = "1model.csv";
                string filepath = @"D:\SMAT_InputData\SSIA_Ozone\";
                if (!Directory.Exists(filepath))
                    Directory.CreateDirectory(filepath);
                filepath += filename;
                if (File.Exists(filepath))
                    File.Delete(filepath);
                fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
                streamWriter = new StreamWriter(fs, Encoding.Default);
                sb.Append("Date,Lat,Lon,Conc,id");
                streamWriter.WriteLine(sb.ToString());
                foreach (KeyValuePair<string, SSIAOzoneData> kvp in dicOzoneDataOutput)
                {
                    SSIAOzoneData model = kvp.Value;
                    if (model.baseOzone < 0.0) continue;
                    sb.Clear();
                    sb.AppendFormat("{0},{1},{2},{3},{4}", new object[] { "2011-1-1", model.lat, model.longitude, model.baseOzone, model.id });
                    streamWriter.WriteLine(sb.ToString());
                }
                streamWriter.Close();
                fs.Close();
                sb.Clear();
                GC.Collect();
            }
            catch
            {

            }
        }

        #endregion

        public static void CalculateDistance(ref Dictionary<string, double[]> dicGrid, Dictionary<string, double[]> dicSource)
        {
            try
            {
                double lat0, long0;
                double lat1, long1;
                foreach (var source in dicSource)
                {
                    lat0 = source.Value[0];
                    long0 = source.Value[1];

                    foreach (var grid in dicGrid)
                    {
                        lat1 = grid.Value[0];
                        long1 = grid.Value[1];

                        double distance = CommonClass.GetDistance(lat0, long0, lat1, long1);
                        if (grid.Value[2] == 0) grid.Value[2] = distance;
                        grid.Value[2] = Math.Min(distance, grid.Value[2]);
                    }
                }
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
            }
        }
    }
}
