/// <summary> /// приведение ряда к условиям плоской местности /// </summary> /// <param name="ms_range">ряд</param> /// <param name="expectancy">повторяемости направлений ветра</param> /// <param name="ms_classes">классы открытости МС</param> /// <param name="water_type">расстояние до водной поверхности</param> /// <returns></returns> public static RawRange ToFlatTerrain(RawRange ms_range, StatisticalRange <WindDirections8> expectancy, Dictionary <WindDirections8, double> ms_classes, WaterDistanceType water_type) { //1. найти Кмс //2. пересчитать ряд RawRange result = new RawRange(); double K0 = (int)water_type; //средневзвешенный коэффициент открытости метеостанции double Kms = 0; foreach (WindDirections8 dir in WindDirections8.N.GetEnumItems()) { if (dir != WindDirections8.Calm && dir != WindDirections8.Undefined && dir != WindDirections8.Variable) { Kms += expectancy[dir] * ms_classes[dir]; } } double k0 = K0 / Kms; result.BeginChange(); foreach (RawItem item in ms_range) { RawItem ni = item.Clone(); ni.Speed = item.Speed * k0; result.Add(ni); } result.EndChange(); return(result); }
/// <summary> /// поднять ряд на высоту с заданными настройками /// </summary> /// <param name="Range">поднимаемый ряд</param> /// <param name="param">настройки</param> /// <param name="actionPercent">действие при изменении процента выполнения</param> /// <param name="actionAfter">действие по окончании выполнения</param> public async static Task <RawRange> ProcessRange(RawRange Range, ElevatorParameters param, Action <int> actionPercent = null, Action <RawRange, SuitAMSResultItem> actionAfter = null) { //найти подходящую АМС //получить из неё параметры m по месяцам //поднять ряд Range на высоту //выбор варианта расчета m: через БД АМС или введенный вручную Dictionary <Months, double> coeffs = null; switch (param.HellmanCoefficientSource) { case HellmanCoefficientSource.AMSAnalog: coeffs = getAMSAnalogCoefficients(param.SelectedAMS.AMS, Range); break; case HellmanCoefficientSource.CustomMonths: coeffs = param.CustomMCoefficientMonths; break; case HellmanCoefficientSource.CustomOne: coeffs = new Dictionary <Months, double>(); for (int i = 1; i <= 12; i++) { coeffs.Add((Months)i, param.CustomMCoefficient); } break; default: throw new Exception("Этот источник данных не реализован"); } coeffs = coeffs ?? throw new ArgumentException("Недопустимые настройки, коэффициенты пересчета на высоту не получены"); //поднять ряд с учетом m по месяцам RawRange res = new RawRange(); res.Position = Range.Position; res.Height = param.ToHeight; res.BeginChange(); return(await Task.Run(() => { double c = 0; foreach (RawItem item in Range) { c++; if (Math.IEEERemainder(c, 100) == 0 && actionPercent != null) { actionPercent.Invoke((int)((c / Range.Count) * 100)); } Months month = (Months)item.Date.Month; double m = coeffs[month]; double oldV = item.Speed; double newV = oldV *Math.Pow(param.ToHeight / param.FromHeight, m); RawItem ni = item.Clone(); ni.Speed = newV; res.Add(ni); } res.EndChange(); if (actionAfter != null) { actionAfter.Invoke(res, param.SelectedAMS); } return res; })); }
/// <summary> /// Загрузка ряда из файла xlsx /// </summary> /// <param name="fileName">адрес файла</param> /// <returns></returns> public override RawRange LoadRange(string fileName) { FileInfo fi = new FileInfo(fileName); using (ExcelPackage excelPackage = new ExcelPackage(fi)) { if (excelPackage.Workbook.Worksheets.Count == 0) { return(null); } ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[0]; if (worksheet.Cells[3, 1].Value == null) { return(null); } string title = worksheet.Cells[1, 1].Value.ToString(); string coordinates = worksheet.Cells[2, 1].Value.ToString(); string name = worksheet.Cells[3, 1].Value.ToString(); string height = worksheet.Cells[2, 2].Value != null ? worksheet.Cells[2, 2].Value.ToString() : "не число"; if (!double.TryParse(height, out double rangeHeight)) { rangeHeight = double.NaN; } RawRange res = new RawRange() { Name = name }; //чтение координат файла string regex = @"^\d+[\.\,].\d*\s+\d+[\.\,].\d*$"; bool isMatch = new Regex(regex).IsMatch(coordinates); PointLatLng coord; if (isMatch) { string[] s = coordinates.Split(' '); double lat = double.Parse(s[0].Trim().Replace('.', Constants.DecimalSeparator)); double lon = double.Parse(s[1].Trim().Replace('.', Constants.DecimalSeparator)); coord = new PointLatLng(lat, lon); } else { coord = PointLatLng.Empty; } res.Position = coord; res.BeginChange(); var arr = worksheet.Cells; for (int i = 5; i <= worksheet.Dimension.Rows; i++) { DateTime dt = getDateTime(arr[i, 1]); double temp = getDouble(arr[i, 2]); double spd = getDouble(arr[i, 5]); double press = getDouble(arr[i, 6]); double wet = getDouble(arr[i, 3]); double dirs = getDouble(arr[i, 4]); try { res.Add(new RawItem() { Date = dt, Direction = dirs, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } catch (Exception) { continue; } } //поиск информации о МС RP5MeteostationInfo meteostation = null; int start = title.IndexOf("ID=") + "ID=".Length; string id_s = title.Substring(start); if (id_s.ToLower() != "nasa" && id_s.ToLower() != "undefined") { meteostation = Vars.RP5Meteostations.GetByID(id_s); } res.Meteostation = meteostation; res.Height = rangeHeight; res.EndChange(); return(res); } }
/// <summary> /// Пытается импортировать файл на основе заданных настроек. При ошибке выбрасывает исключение WindEnergyException с информацией или ArgumentException при недопустимых настройках /// </summary> /// <returns></returns> /// <param name="count">количество считываемых строк, начиная со StartLine</param> public RawRange Import(long count = long.MaxValue) { CheckParameters(); //проверка параметров //Импорт данных string data = GetText(count); RawRange res = new RawRange(); res.BeginChange(); string[] lines = data.Split('\r'); int line_i = 0; foreach (string line in lines) { line_i++; string[] arr = new Regex("w*" + Delimeter + "w*").Split(line.Replace("\n", "")); if (arr.Length <= 1) { continue; } List <ImportFields> fields = this.Columns.Keys.ToList(); RawItem item = new RawItem(); foreach (ImportFields field in fields) { int index = Columns[field] - 1; string value = arr[index]; if (Trimmers != null && Trimmers.Length > 0) { value = value.Trim(Trimmers); } try { switch (field) { case ImportFields.Date: item.Date = DateTime.Parse(value); break; case ImportFields.Direction: switch (DirectionUnit) { case DirectionUnits.Degrees: item.Direction = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case DirectionUnits.TextRP5: item.DirectionRhumb = RP5ru.GetWindDirectionFromString(value); break; case DirectionUnits.None: throw new ArgumentException("Не заданы единицы измерения для направления"); default: throw new WindEnergyException("Эта единица измерений не реализована"); } break; case ImportFields.Pressure: switch (PressureUnit) { case PressureUnits.KPa: item.Pressure = double.Parse(value.Replace('.', Constants.DecimalSeparator)) * Constants.MMHGART_IN_1KPA; //перевод в мм рт. ст. break; case PressureUnits.mmHgArt: item.Pressure = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case PressureUnits.None: throw new ArgumentException("Не заданы единицы измерения для давления"); default: throw new WindEnergyException("Эта единица измерений не реализована"); } break; case ImportFields.Wetness: switch (WetnessUnit) { case WetnessUnits.Percents: item.Wetness = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case WetnessUnits.Parts: item.Wetness = double.Parse(value.Replace('.', Constants.DecimalSeparator)) * 100d; //перевод в % break; case WetnessUnits.None: throw new ArgumentException("Не заданы единицы измерения для влажности"); default: throw new WindEnergyException("Эта единица измерений не реализована"); } break; case ImportFields.Temperature: item.Temperature = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; case ImportFields.Speed: item.Speed = double.Parse(value.Replace('.', Constants.DecimalSeparator)); break; default: throw new WindEnergyException("Этот параметр не реализован"); } } catch (Exception ex) { throw new WindEnergyException($"Не удалось распознать строку \"{value}\" как значение поля {field.Description()} в строке {line_i}", ex.Message); } } res.Add(item); } if ((bool)BindNearestMS) { res.Meteostation = Vars.RP5Meteostations.GetNearestMS(this.Coordinates); } res.Position = this.Coordinates; res.Name = Path.GetFileNameWithoutExtension(this.FilePath); res.EndChange(); res.PerformRefreshQuality(); return(res); }
/// <summary> /// поднять ряд на высоту с заданными настройками /// </summary> /// <param name="Range">поднимаемый ряд</param> /// <param name="param">настройки</param> /// <param name="actionPercent">действие при изменении процента выполнения</param> /// <param name="actionAfter">действие по окончании выполнения</param> public static void ProcessRange(RawRange Range, TerrainParameters param, Action <int> actionPercent, Action <RawRange, FlugerMeteostationInfo> actionAfter) { RawRange result = new RawRange(); result.Position = param.PointCoordinates; result.Name = $"Ряд в точке {param.PointCoordinates.ToString(3)}"; result.BeginChange(); switch (param.TerrainType) { case TerrainType.Macro: Dictionary <WindDirections8, double> k0 = getTerrainMacroK0(param.MSClasses, param.PointClasses); //получаем коэффициенты для плоского рельефа //пересчет всех скоростей ряда double c = 0; foreach (var item in Range) { WindDirections8 wd8 = item.DirectionRhumb8; if (wd8 == WindDirections8.Calm || wd8 == WindDirections8.Undefined || wd8 == WindDirections8.Variable) { continue; } double nspeed = item.Speed * k0[wd8]; //для направления в этой точке пересчитываем скорости RawItem nitem = item.Clone(); nitem.Speed = nspeed; result.Add(nitem); c++; if (Math.IEEERemainder(c, 100) == 0 && actionPercent != null) { actionPercent((int)((c / Range.Count) * 100)); } } break; case TerrainType.Meso: //мезоклиматический коэффициент double Km = (param.MesoclimateCoefficient.Value.From + param.MesoclimateCoefficient.Value.To) / 2d; //среднее внутри диапазона //выбор преобладающих направлений ветра List <WindDirections8> dominants = GetRhumbsDominants(Range); //пересчет ряда только для преобладающих направлений foreach (RawItem item in Range) { RawItem ni = item.Clone(); ni.Speed = dominants.Contains(ni.DirectionRhumb8) ? ni.Speed * Km : ni.Speed; result.Add(ni); } break; case TerrainType.Micro: //выбор преобладающих направлений ветра List <WindDirections8> directs = GetRhumbsDominants(Range); //пересчет ряда только для преобладающих направлений foreach (RawItem item in Range) { double Kmk = selectMicroclimateCoefficient(item.Speed, param.MicroclimateCoefficient, param.AtmosphereStratification); RawItem ni = item.Clone(); ni.Speed = directs.Contains(ni.DirectionRhumb8) ? ni.Speed * Kmk : ni.Speed; result.Add(ni); } break; default: throw new Exception("Этот тип рельефа не реализован"); } result.Height = Range.Height; result.EndChange(); actionAfter(result, param.FlugerMeteostation); return; }
/// <summary> /// загрузка ряда из формата WindEnergy /// </summary> /// <param name="filename"></param> /// <returns></returns> private RawRange loadCSVFile(string filename) { StreamReader sr = new StreamReader(filename, Encoding.UTF8); string title = sr.ReadLine(); string coordinates = sr.ReadLine(); string name = sr.ReadLine(); sr.ReadLine();//пропуск заголовка таблицы string data = sr.ReadToEnd(); sr.Close(); RawRange res = new RawRange() { Name = name }; //чтение координат файла string regex = @"^\d+[\.\,].\d*\s+\d+[\.\,].\d*$"; bool isMatch = new Regex(regex).IsMatch(coordinates); PointLatLng coord; if (isMatch) { string[] s = coordinates.Split(' '); double lat = double.Parse(s[0].Trim().Replace('.', Constants.DecimalSeparator)); double lon = double.Parse(s[1].Trim().Replace('.', Constants.DecimalSeparator)); coord = new PointLatLng(lat, lon); } else { coord = PointLatLng.Empty; } res.Position = coord; res.BeginChange(); string[] lines = data.Split('\n'); foreach (string line in lines) { string[] elems = line.Split(';'); if (elems.Length < 6) { continue; } if (elems[3] == "") { continue; } if (elems[4] == "") { continue; } double temp = elems[1] == "" ? double.NaN : double.Parse(elems[1].Replace('.', Constants.DecimalSeparator)); DateTime dt = DateTime.Parse(elems[0]); double spd = double.Parse(elems[4].Replace('.', Constants.DecimalSeparator)); double press = double.Parse(elems[5].Replace('.', Constants.DecimalSeparator)); double wet = elems[2] == "" ? double.NaN : double.Parse(elems[2].Replace('.', Constants.DecimalSeparator)); double dirs = double.Parse(elems[3].Replace('.', Constants.DecimalSeparator)); try { res.Add(new RawItem() { Date = dt, Direction = dirs, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } catch (Exception) { continue; } } //поиск информации о МС RP5MeteostationInfo meteostation = null; int start = title.IndexOf("ID=") + "ID=".Length; string id_s = title.Substring(start); meteostation = Vars.RP5Meteostations.GetByID(id_s); res.Meteostation = meteostation; res.EndChange(); return(res); }
/// <summary> /// Загрузить ряд из файла csv, полученного с сайта /// </summary> /// <param name="file">файл csv</param> /// <param name="meteostation">Привязка к метеостанции. Если null, то будет найдена из БД по ID из заголовка</param> /// <returns></returns> public static RawRange LoadCSV(string file, RP5MeteostationInfo meteostation = null) { using (StreamReader sr = new StreamReader(file, Encoding.UTF8, true)) { RawRange res = new RawRange(); res.BeginChange(); //приостановка обработки событий изменения ряда //определение формата файла csv MeteoSourceType type; string title = sr.ReadLine(); if (title.Contains("WMO_ID")) { type = MeteoSourceType.Meteostation; } else if (title.Contains("METAR")) { type = MeteoSourceType.Airport; } else { throw new Exception("Файл повреждён или имеет неизвестный формат данных rp5.ru"); } //пропуск пустых строк (одна уже пропущена при чтении заголовка) for (int i = 0; i < 6; i++) { sr.ReadLine(); } switch (type) { case MeteoSourceType.Meteostation: //загрузка архива с метеостанции string data = sr.ReadToEnd(); sr.Close(); string[] lines = data.Replace("\"", "").Split('\n'); foreach (string line in lines) { string[] elems = line.Split(';'); if (elems.Length < 8) { continue; } if (elems[6] == "") { continue; } if (elems[7] == "") { continue; } double temp = elems[1] == "" ? double.NaN : double.Parse(elems[1].Replace('.', Constants.DecimalSeparator)); DateTime dt = DateTime.Parse(elems[0]); double spd = double.Parse(elems[7].Replace('.', Constants.DecimalSeparator)); double wet = elems[5] == "" ? double.NaN : double.Parse(elems[5].Replace('.', Constants.DecimalSeparator)); double press = elems[2] == "" ? double.NaN : double.Parse(elems[2].Replace('.', Constants.DecimalSeparator)); string dirs = elems[6]; WindDirections16 direct = GetWindDirectionFromString(dirs); try { res.Add(new RawItem() { Date = dt, DirectionRhumb = direct, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } catch (Exception) { continue; } } //поиск информации о МС if (meteostation == null) { int start = title.IndexOf("WMO_ID=") + "WMO_ID=".Length; int end = title.IndexOf(',', start); string id_s = title.Substring(start, end - start); meteostation = Vars.RP5Meteostations.GetByID(id_s); } break; case MeteoSourceType.Airport: //загрузка архива с аэропорта string data2 = sr.ReadToEnd(); sr.Close(); string[] lines2 = data2.Replace("\"", "").Split('\n'); foreach (string line in lines2) { string[] elems = line.Split(';'); if (elems.Length < 8) { continue; } if (elems[5] == "") { continue; } if (elems[6] == "") { continue; } double temp = elems[1] == "" ? double.NaN : double.Parse(elems[1].Replace('.', Constants.DecimalSeparator)); DateTime dt = DateTime.Parse(elems[0]); double spd = double.Parse(elems[6].Replace('.', Constants.DecimalSeparator)); double wet = elems[4] == "" ? double.NaN : double.Parse(elems[4].Replace('.', Constants.DecimalSeparator)); double press = elems[2] == "" ? double.NaN : double.Parse(elems[2].Replace('.', Constants.DecimalSeparator)); string dirs = elems[5]; WindDirections16 direct = RP5ru.GetWindDirectionFromString(dirs); res.Add(new RawItem() { Date = dt, DirectionRhumb = direct, Speed = spd, Temperature = temp, Wetness = wet, Pressure = press }); } //поиск информации о МС if (meteostation == null) { int start = title.IndexOf("METAR=") + "METAR=".Length; int end = title.IndexOf(',', start); string id_s = title.Substring(start, end - start); meteostation = Vars.RP5Meteostations.GetByCC_code(id_s); } break; case MeteoSourceType.UnofficialMeteostation: throw new Exception("Этот тип файла не поддерживается"); } res.Meteostation = meteostation; res.EndChange(); return(res); } }