public static float GetRefTemp(EarthModel earth, SimDateTime sdt, int r, int c) { string key = string.Format("{0}_{1}_{2}", sdt.DayOfYear, r, c); lock (_refTemp) { if (_refTemp.ContainsKey(key) == false) { int lat = EarthModel.MaxLat - r; float rt = GetRefTemp_ByLatitude_MidLevel(sdt, lat) + AbsoluteConstants.WaterFreezePoint; float dt = rt - AbsoluteConstants.WaterFreezePoint; float f = 1.2f; var wl = earth.SFC.WL[r, c]; if (wl == 0) { rt = AbsoluteConstants.WaterFreezePoint + dt * f; } else { rt = AbsoluteConstants.WaterFreezePoint + dt / f; } _refTemp.Add(key, rt - AbsoluteConstants.WaterFreezePoint); } return(_refTemp[key]); } }
public Atmosphere(EarthModel earth, bool loadFromStateFiles, float defaultValue = 0) { this.Earth = earth; SeaLevel = new SeaLevel(earth, loadFromStateFiles, defaultValue); MidLevel = new MidLevel(earth, loadFromStateFiles, defaultValue); TopLevel = new TopLevel(earth, loadFromStateFiles, defaultValue); JetLevel = new JetLevel(earth, loadFromStateFiles, defaultValue); if (loadFromStateFiles == false) { if (defaultValue == 0) { TopLevel.LoadInitialConditions(); MidLevel.LoadInitialConditions(); CalculateAirMassType(); SeaLevel.LoadInitialConditions(); } else { AirMass = MatrixFactory.Init(defaultValue); } } else { AirMass = FileSupport.Load(Earth.UTC.Title, "M_00_MAP"); } }
public static float GetRefTempYearlyDelta_MidLevel(EarthModel earth, int r, int c) { string key = string.Format("{0}_{1}", r, c); lock (_refTempYearlyDelta) { if (_refTempYearlyDelta.ContainsKey(key) == false) { float tRefMin = 100; float tRefMax = -100; SimDateTime sdtStart = earth.UTC; for (int i = 0; i < 365; i += 5) { SimDateTime sdt = sdtStart.AddHours((int)AbsoluteConstants.HoursPerDay * i); float tRef = GetRefTemp(earth, sdt, r, c); tRefMin = Math.Min(tRefMin, tRef); tRefMax = Math.Max(tRefMax, tRef); } float delta = (tRefMax - tRefMin); _refTempYearlyDelta.Add(key, delta); } } return(_refTempYearlyDelta[key]); }
public Simulation(SimDateTime sdtStart, SimDateTime sdtEnd, int snaphotLength, bool loadFromStateFiles) { Start = sdtStart; End = sdtEnd; _earth = new EarthModel(sdtStart, loadFromStateFiles, snaphotLength); _earth.Save(sdtStart.Title); }
public SimDateTimeRangeStats(EarthModel earth) { MeanValues = new Atmosphere(earth, false, float.Epsilon); MinValues = new Atmosphere(earth, false, float.MaxValue); MaxValues = new Atmosphere(earth, false, float.MinValue); MeanValuesSFC = new SurfaceLevel(earth, false, float.Epsilon); MinValuesSFC = new SurfaceLevel(earth, false, float.MaxValue); MaxValuesSFC = new SurfaceLevel(earth, false, float.MinValue); }
public static bool SimBreakPoint(int r, int c, EarthModel model = null) { SimDateTime compareTo = new SimDateTime("2019-06-20_00"); #if HAVE_TESTSIMBREAKPOINT if (model == null || model.UTC.GetHoursOffset(compareTo) >= 0) { return(r == EarthModel.MaxLat - (int)SimConstants.TEST_Lat && c == EarthModel.MaxLon + (int)SimConstants.TEST_Lon); } #endif return(false); }
/// <summary> /// найти все метеостанции из списка mts, которые находятся в радиусе radius от заданной точки coordinates /// </summary> /// <param name="coordinates"></param> /// <param name="radius"></param> /// <param name="addOwn">Если истина, то если точно в точке coordinates есть МС, то она тоже будет добавлена</param> /// <returns></returns> protected virtual List <BaseMeteostationInfo> GetNearestMS(PointLatLng coordinates, double radius, bool addOwn = false) { List <BaseMeteostationInfo> res = new List <BaseMeteostationInfo>(); foreach (var ms in this.List.Cast <BaseMeteostationInfo>()) { double dist = EarthModel.CalculateDistance(ms.Position, coordinates); if ((dist < radius && dist > COORDINATES_OVERLAP) || (dist < COORDINATES_OVERLAP && addOwn)) // если попадает в радиус и не совпадает или совпадает и надо добавлять { res.Add(ms); } } return(res); }
/// <summary> /// найти ближайшую точку в словаре к заданной /// </summary> /// <param name="coordinates">заданная точка</param> /// <returns></returns> private PointLatLng getNearest(PointLatLng coordinates) { double min = double.MaxValue; PointLatLng res = PointLatLng.Empty; foreach (var p in this.limits.Keys) { double f = EarthModel.CalculateDistance(p, coordinates); if (f < min) { min = f; res = p; } } return(res); }
public static SimDateTimeRange BuildRange(SimDateTime dtStart, int rangeSize) { EarthModel earth = new EarthModel(dtStart, true, (int)AbsoluteConstants.HoursPerDay); if (SimulationData.AvailableSnapshots.Contains(dtStart)) { SimDateTime sdt = dtStart.AddHours((rangeSize - 1) * earth.SnapshotLength); SimDateTime dtEnd = SimulationData.SelectNearestSnapshot(sdt); if (dtEnd != null) { return(new SimDateTimeRange(earth, dtStart, dtEnd)); } } return(null); }
/// <summary> /// на основе ряда наблюдений на высоте 10м подобрать АМС и выбрать ряд коэффициентов m для поднятия скорости на высоту /// </summary> /// <param name="range">ряд наблюдений на МС</param> /// <param name="coordinates">координаты ряда</param> /// <param name="MSMeteostations">БД АМС</param> /// <param name="searchRadius">расстояние для фильтрации АМС в метрах. Если задано NaN, то фильтрация по расстоянию проводить не будет</param> /// <param name="maximalRelativeSpeedDeviation">максимальное среднеквадратичное отклонение относительной скорости. NaN, если не надо учитывать</param> /// <returns></returns> public static SuitAMSResult GetSuitAMS(RawRange range, PointLatLng coordinates, AMSMeteostationDatabase MSMeteostations, double searchRadius, double maximalRelativeSpeedDeviation) { //посчитать среднемесячные относительные скорости для МС //выбрать АМС из заданного радиуса //посчитать относительные скорости на всех АМС //найти наиболее подходящую АМС по наименьшему среднеквадратичному отклонению относительных скоростей //относительные среднемесячные скорости на МС Dictionary <Months, double> msRelatives = getRelativeAverageMonthSpeeds(range, out bool allMonth); //выбор АМС в заданном радиусе List <AMSMeteostationInfo> amss = double.IsNaN(searchRadius) ? MSMeteostations.List : MSMeteostations.GetNearestMS(coordinates, searchRadius, true); //выбираем все АМС в радиусе if (amss == null) { return(null); } //поиск АМС с минимальным среднеквадр отклонением относительных скоростей SuitAMSResult res = new SuitAMSResult(); double minDev = double.MaxValue; SuitAMSResultItem minItem = null; foreach (AMSMeteostationInfo ams in amss) { SuitAMSResultItem item = new SuitAMSResultItem(); item.Deviation = Math.Sqrt(msRelatives.Average((kv) => { return(Math.Pow(kv.Value - ams.RelativeSpeeds[kv.Key], 2)); })); //корень(среднее ((KjМС - KjАМС)^2)), j - номер месяца item.AMS = ams; item.AllMonthInRange = allMonth; item.IsDeviationFailed = !double.IsNaN(maximalRelativeSpeedDeviation) && item.Deviation > maximalRelativeSpeedDeviation; item.Distance = EarthModel.CalculateDistance(coordinates, ams.Position); res.Add(item); //ищем минимальный элемент if (minDev > item.Deviation) { minDev = item.Deviation; minItem = item; } } res.AllMonthInRange = allMonth; res.RangeRelativeSpeeds = msRelatives; res.ItemWithMinimalDeviation = minItem; return(res); }
public AtmosphericLevel(EarthModel earth, int levelType, bool loadFromStateFiles, float defaultValue = 0) { this.Earth = earth; _levelType = levelType; if (loadFromStateFiles) { P = FileSupport.Load(Earth.UTC.Title, string.Format("P_{0:d2}_MAP", _levelType)); T = FileSupport.Load(Earth.UTC.Title, string.Format("T_{0:d2}_MAP", _levelType)); H = FileSupport.Load(Earth.UTC.Title, string.Format("H_{0:d2}_MAP", _levelType)); } else if (defaultValue != 0) { P = MatrixFactory.Init(defaultValue); T = MatrixFactory.Init(defaultValue); H = MatrixFactory.Init(defaultValue); } }
/// <summary> /// найти ближайшую МС для заданных координат и в заданном радиусе от точки /// </summary> /// <param name="coordinates"></param> /// <param name="maxRadius">радиус поиска в метрах</param> /// <returns></returns> protected virtual BaseMeteostationInfo GetNearestMS(PointLatLng coordinates, double maxRadius = double.MaxValue) { if (coordinates.IsEmpty) { return(null); } BaseMeteostationInfo res = null; bool useMaxRadius = maxRadius != double.MaxValue; double min = double.MaxValue; foreach (var p in this.List.Cast <BaseMeteostationInfo>()) { double f = EarthModel.CalculateDistance(p.Position, coordinates); if (f < COORDINATES_OVERLAP) { // ближайшая метеостанция не должна быть той же самой continue; } if (useMaxRadius) { if (f < min && f > COORDINATES_OVERLAP && f < maxRadius) { min = f; res = p; } } else { if (f < min) { min = f; res = p; } } } if (min == double.MaxValue) { return(null); } return(res); }
public SimDateTimeRange(EarthModel earth, SimDateTime dtStart, SimDateTime dtEnd) { this.Start = dtStart; this.End = dtEnd; this.Earth = earth; AtmList = new List <Atmosphere>(); SfcList = new List <SurfaceLevel>(); for (SimDateTime sdt = dtStart; sdt.CompareTo(dtEnd) <= 0; sdt = sdt.AddHours(earth.SnapshotLength)) { Atmosphere atm = null; SurfaceLevel sfc = null; try { earth.SetUTC(sdt); atm = new Atmosphere(earth, true); sfc = new SurfaceLevel(earth, true); } catch { atm = null; sfc = null; } if (atm != null) { AtmList.Add(atm); } if (sfc != null) { SfcList.Add(sfc); } } }
public static DenseMatrix GetRefTemp(EarthModel earth) { return(MatrixFactory.New((r, c) => GetRefTemp(earth, r, c))); }
/// <summary> /// ищет наиболее подходящую к заданной точке МС и получает её ряд. Если ряд не найден, то возвращает null /// </summary> /// <param name="coordinates"></param> /// <param name="r"></param> /// <param name="actionPercent"></param> /// <param name="Range">ряд, для которого подбирается функция</param> /// <exception cref="GetBaseRangeException">Возвращает иснформацию о параметрах, мешающих получить ближайшую МС</exception> /// <returns></returns> internal static RawRange TryGetBaseRange(RawRange Range, PointLatLng coordinates, out double r, Action <int, string> actionPercent) { bool nlaw = CheckNormalLaw(Range, Vars.Options.NormalLawPirsonCoefficientDiapason); if (!nlaw) { throw new WindEnergyException("Исходный ряд не подчиняется нормальному закону распределения"); } DateTime from = Range.Min((ri) => ri.Date).Date, to = Range.Max((ri) => ri.Date).Date; List <RP5MeteostationInfo> mts = Vars.RP5Meteostations.GetNearestMS(coordinates, Vars.Options.NearestMSRadius, false); Dictionary <double, double> funcSpeed = Range.GetFunction(MeteorologyParameters.Speed); //функция скорости на заданном ряде RawRange res = null; double rmax = double.MinValue, total_rmax = double.MinValue; RP5ru provider = new RP5ru(Vars.Options.CacheFolder + "\\rp5.ru"); for (int i = 0; i < mts.Count; i++) { if (actionPercent != null) { actionPercent.Invoke((int)((i * 1d / mts.Count) * 100d), "Поиск подходящей МС..."); } RP5MeteostationInfo m = mts[i]; //если нет диапазона измерений в БД, то загружаем с сайта if (m.MonitoringFrom == DateTime.MinValue) { provider.GetMeteostationExtInfo(ref m); } //если для этой МС нет наблюдений в этом периоде, то переходим на другую if (m.MonitoringFrom > from) { continue; } //загрузка ряда с очередной МС RawRange curRange = null; try { curRange = provider.GetRange(from, to, m); } catch (WindEnergyException wex) // если не удалось получить ряд этой МС, то переходим к следующей { continue; } curRange = new Checker().ProcessRange(curRange, new CheckerParameters(LimitsProviders.StaticLimits, curRange.Position), out CheckerInfo info, null); //исправляем ошибки //СКОРОСТЬ MeteorologyParameters parameter = MeteorologyParameters.Speed; Dictionary <double, double> funcSpeedCurrentNearest = curRange.GetFunction(parameter); //функция скорости на текущей МС //проверка на нормальный закон распределения bool normal = CheckNormalLaw(curRange, Vars.Options.NormalLawPirsonCoefficientDiapason); if (!normal) { continue; } //расчёт и проверка коэфф корреляции List <double>[] table = calcTableCoeff(funcSpeed, funcSpeedCurrentNearest); //таблица для расчет коэффициентов double current_r = getParameterR(table); //коэффициент корреляции //общий максимальный коэфф корреляции if (current_r > total_rmax) { total_rmax = current_r; } //проверяем, можно ли взять эту МС if (current_r > rmax) { //истина, если надо проверять этот параметр на допустимый диапазон корреляции bool needCheck = Vars.Options.MinimalCorrelationControlParametres.Contains(parameter); if ((needCheck && current_r >= Vars.Options.MinimalCorrelationCoeff) || !needCheck) { rmax = current_r; res = curRange; } } } r = rmax; if (res == null) { RP5MeteostationInfo mi = Vars.RP5Meteostations.GetNearestMS(coordinates); double l = EarthModel.CalculateDistance(mi.Position, coordinates); throw new GetBaseRangeException(total_rmax, Vars.Options.MinimalCorrelationCoeff, l, mts.Count, Vars.Options.NearestMSRadius, coordinates); } return(res); }
/// <summary> /// выбор текста для рекомендаций, какой тип рельефа лучше использовать /// </summary> /// <param name="range"></param> /// <param name="pointCoordinates"></param> /// <param name="geoinfo"></param> /// <returns></returns> public static Dictionary <string, Color> GetRecommendation(RawRange range, PointLatLng pointCoordinates, IGeoInfoProvider geoinfo) { if (range.Position.IsEmpty) { throw new WindEnergyException("Не заданы координаты метеостанции"); } if (pointCoordinates.IsEmpty) { throw new WindEnergyException("Не заданы координаты точки ВЭС"); } if (geoinfo == null) { throw new ArgumentNullException(nameof(geoinfo)); } Dictionary <string, Color> result = new Dictionary <string, Color>(); double L = EarthModel.CalculateDistance(range.Position, pointCoordinates) / 1000; //расстояние вкилометрах между МС и точкой ВЭС double Hms = geoinfo.GetElevation(range.Position); //высота точки МС double Hpoint = geoinfo.GetElevation(pointCoordinates); //высота точки ВЭС double Habs = Math.Max(Hms, Hpoint); //максимальная высота на у.м. double dH = Math.Abs(Hpoint - Habs); //перепад высот между МС и ВЭС StatisticalRange <WindDirections8> expectancy = StatisticEngine.GetDirectionExpectancy(range, GradationInfo <WindDirections8> .Rhumb8Gradations); //повторяемости скорости ветра по 8 румбам var maxes = expectancy.Values.OrderByDescending((d) => d).ToList(); if (maxes[0] < 0.2) //если все румбы меньше 20%, то нет преобладающего направления { result.Add("Нет преобладающего направления ветра", Color.Black); } else//выбор преобладающих направлений ветра { var dirs = GetRhumbsDominants(range, expectancy); string ln = dirs.Aggregate("", (str, dir) => str + $"{dir.Description()} ({Math.Round(expectancy[dir] * 100, 2)}%), ").Trim(new char[] { ' ', ',' }); result.Add("Преобладающие направления ветра: " + ln, Color.Black); } if (Hms > 750) { result.Add($"Высота точки МС больше 750 м над у. м. ({Hms:0.0} м), не рекомендуеся выполнять преобразование", Color.Red); } else if (Hpoint > 750) { result.Add($"Высота точки ВЭС больше 750 м над у. м. ({Hpoint:0.0} м), не рекомендуеся выполнять преобразование", Color.Red); } else { if (L > 50 && dH <= 750 && Habs <= 750) //макрорельеф { result.Add($"Рекомендуется выбрать макрорельеф (L={L:0.0} км, Δh={dH:0.0} м)", Color.Green); } if (L > 3 && L <= 50 && dH <= 750 && Habs <= 750) //мезорельеф { result.Add($"Рекомендуется выбрать мезорельеф (L={L:0.0} км, Δh={dH:0.0} м)", Color.Green); } if (L <= 3 && dH <= 80 && Habs <= 750) //микрорельеф { result.Add($"Рекомендуется выбрать микрорельеф (L={L:0.0} км, Δh={dH:0.0} м)", Color.Green); } } return(result); }
public static DenseMatrix GetRefTempYearlyDelta_MidLevel(EarthModel earth) { return(MatrixFactory.New((r, c) => GetRefTempYearlyDelta_MidLevel(earth, r, c))); }
public static float GetRefTemp(EarthModel earth, int r, int c) { return(GetRefTemp(earth, earth.UTC, r, c)); }