private void buttonElevate_Click(object sender, EventArgs e) { Cursor = Cursors.WaitCursor; if (!double.TryParse(textBoxToHeight.Text.Trim().Replace('.', Constants.DecimalSeparator), out double new_height)) { _ = MessageBox.Show(this, $"Не удалось распознать {textBoxToHeight.Text} как число", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!double.TryParse(textBoxFromHeight.Text.Trim().Replace('.', Constants.DecimalSeparator), out double old_height)) { _ = MessageBox.Show(this, $"Не удалось распознать {textBoxFromHeight.Text} как число", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!double.TryParse(textBoxRadius.Text.Trim().Replace('.', Constants.DecimalSeparator), out double radius)) { _ = MessageBox.Show(this, $"Не удалось распознать {textBoxRadius.Text} как число", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (!double.TryParse(textBoxCoeffM.Text.Trim().Replace('.', Constants.DecimalSeparator), out double m)) { _ = MessageBox.Show(this, $"Не удалось распознать {textBoxCoeffM.Text} как число", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } radius *= 1000; //перевод км в метры if (hellmanCoeffSource == HellmanCoefficientSource.None) { _ = MessageBox.Show(this, "Что-то пошло не так, попробуйте другие настройки", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); } Action <int> action = new Action <int>((percent) => { try { if (this.InvokeRequired) { _ = Invoke(new Action(() => { progressBar1.Value = percent; })); } else { progressBar1.Value = percent; } } catch (Exception) { } }); Action <RawRange, SuitAMSResultItem> actionAfter = new Action <RawRange, SuitAMSResultItem>((rawRange, selectedAMS) => { _ = this.Invoke(new Action(() => { string AMStext = selectedAMS != null ? $"На основе данных АМС {selectedAMS.AMS.Name} {selectedAMS.AMS.Position}\r\nОтклонение среднемесячных скоростей: {selectedAMS.Deviation:0.000} {(selectedAMS.AllMonthInRange ? "" : "\r\nВНИМАНИЕ!! В исходном ряде представлены не все месяцы. Поэтому подбор подходящей АМС может быть неточным")}" : ""; rawRange.Name = "Ряд на высоте " + new_height + " м"; _ = MessageBox.Show(this, $"Скорости ветра пересчитаны на высоту {new_height} м\r\n{((!string.IsNullOrWhiteSpace(AMStext)) ? AMStext : "")}", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Information); if (rawRange == null) { DialogResult = DialogResult.Cancel; } else { DialogResult = DialogResult.OK; Result = rawRange; } Cursor = Cursors.Arrow; Result = rawRange; Close(); })); }); try { //если в ряде нет координат и надо искать АМС-аналог, то выбираем (для подбора подходящей АМС) if (range.Position.IsEmpty && hellmanCoeffSource == HellmanCoefficientSource.AMSAnalog) { FormSelectMapPointDialog fsp = new FormSelectMapPointDialog("Выберите координаты ряда " + range.Name, PointLatLng.Empty, Vars.Options.CacheFolder, Resources.rp5_marker, Vars.Options.MapProvider); if (fsp.ShowDialog(this) == DialogResult.OK) { range.Position = fsp.Result; } else { Cursor = Cursors.Arrow; return; } } //основные параметры пересчета ряда на высоту ElevatorParameters parameters = new ElevatorParameters() { FromHeight = old_height, ToHeight = new_height, Coordinates = range.Position, SearchRaduis = checkBoxUseRadius.Checked ? radius : double.NaN, MaximalRelativeSpeedDeviation = Vars.Options.UseSuitAMSMaximalRelativeSpeedDeviation ? Vars.Options.SuitAMSMaximalRelativeSpeedDeviation : double.NaN, CustomMCoefficient = checkBoxCustomCoeffM.Checked ? m : double.NaN, CustomMCoefficientMonths = MonthsHellmanValues, HellmanCoefficientSource = hellmanCoeffSource }; //если способ пересчета АМС-аналог, то надо предоставить выбор АМС для расчетов if (hellmanCoeffSource == HellmanCoefficientSource.AMSAnalog) { //находим все подходящие АМС SuitAMSResult suitAMSList = AMSSupport.GetSuitAMS( range, range.Position, Vars.AMSMeteostations, checkBoxUseRadius.Checked ? radius : double.NaN, Vars.Options.UseSuitAMSMaximalRelativeSpeedDeviation ? Vars.Options.SuitAMSMaximalRelativeSpeedDeviation : double.NaN ); //открывам диалоговое окно списка АМС FormRangeElevatorConfirmation frec = new FormRangeElevatorConfirmation(suitAMSList); if (frec.ShowDialog(this) == DialogResult.OK) { parameters.SelectedAMS = frec.Result; } else //если ничего не выбрали, то выходим { Cursor = Cursors.Arrow; return; } } RangeElevator.ProcessRange(range, parameters, action, actionAfter); //запускаем обработку ряда } catch (WebException exc) { Cursor = Cursors.Arrow; _ = MessageBox.Show(this, exc.Message, "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); DialogResult = DialogResult.Cancel; } catch (WindEnergyException wex) { Cursor = Cursors.Arrow; _ = MessageBox.Show(this, wex.Message, "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); } catch (ApplicationException exc) { Cursor = Cursors.Arrow; _ = MessageBox.Show(this, exc.Message + "\r\nПопробуйте уменьшить длину ряда", "Расчет скорости ветра на высоте башни ВЭУ", MessageBoxButtons.OK, MessageBoxIcon.Warning); DialogResult = DialogResult.Cancel; } catch (Exception ex) { Cursor = Cursors.Arrow; _ = MessageBox.Show(this, "Произошла ошибка:\r\n" + ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); DialogResult = DialogResult.Cancel; } }
/// <summary> /// основной расчет для ВЭУ по заданному ряду /// </summary> /// <param name="range"></param> /// <param name="equipment"></param> /// <param name="h"></param> /// <param name="startHeight"></param> /// <param name="ams">выбранная АМС для пересчета на высоту или null, если не надо проводить пересчет</param> /// <param name="needRecalcWithAirDensity"></param> /// <returns></returns> public async static Task <PowerCalculatorResult> Calculate(RawRange range, EquipmentItemInfo equipment, double h, double startHeight, SuitAMSResultItem ams, bool needRecalcWithAirDensity) { //пересчитать ряд на высоту h (считаем, что ряд на высоте startHeight) //расчитать Ni для каждого наблюдения //расчитать основные показатели Э, kиум, Эуд, hиум //расчитать кривую обеспеченности //проверка, надо ли пересчитывать скорости ветра на высоту RawRange altedRange; if (ams != null) { altedRange = await RangeElevator.ProcessRange(range, new ElevatorParameters() { ToHeight = h, Coordinates = range.Position, HellmanCoefficientSource = HellmanCoefficientSource.AMSAnalog, SelectedAMS = ams, FromHeight = startHeight }); } else { altedRange = range; } //если надо, то пересчитываем мощностную характеристику с учетом плотности воздуха Dictionary <double, double> characteristic; if (needRecalcWithAirDensity) { characteristic = RecalcPerfomanceCharacteristicWithAirDensity(range.AirDensity, equipment.PerformanceCharacteristic, equipment); } else { characteristic = equipment.PerformanceCharacteristic; } //расчет мощности для каждого наблюдения и годовой выработки LinearInterpolateMethod interpolator = new LinearInterpolateMethod(characteristic); Dictionary <double, double> production = new Dictionary <double, double>(); Dictionary <DateTime, double> productionRange = new Dictionary <DateTime, double>(); Dictionary <Months, double> energyByMonth = new Dictionary <Months, double>(); double totalE = 0; for (int i = 0; i < altedRange.Count; i++) { RawItem item = altedRange[i]; double N; if (!interpolator.InBounds(item.Speed)) { N = 0; //мощность в кВт } else { N = interpolator.GetValue(item.Speed); //мощность в кВт } production.Add(item.DateArgument, N); productionRange.Add(item.Date, N); //расчет выработки if (i > 0) { double energyBit = N * (item.DateArgument - altedRange[i - 1].DateArgument) / 60; //перевод в часы (DateArgumet в минутах) totalE += energyBit; //суммарная выработка в кВт*ч //выработка по месяцам Months month = (Months)item.Date.Month; if (energyByMonth.ContainsKey(month)) { energyByMonth[month] += energyBit; } else { energyByMonth.Add(month, energyBit); } } } //поскольку ряд мб произвольной длины, то надо привести выработку к среднегодовой //коэффициент пересчета к одному году double yearKoeff = 8760 / ((altedRange.Last().Date - altedRange.First().Date).TotalHours); double E = totalE * yearKoeff; //коэфф использования установленной мощности double kium = E / (equipment.Power * 8760); //выработка уже приведена к году, используем как есть //удельная выработка double Edensity = E / (Math.PI * Math.Pow(equipment.Diameter, 2) / 4); // Эгод/Fом //число часов использования установленной мощности double hium = E / equipment.Power; //выработка уже приведена к году, используем как есть PowerCalculatorResult result = new PowerCalculatorResult() { YearEnergy = E, TotalEnergy = totalE, EnergyByMonth = energyByMonth, EDensity = Edensity, Kium = kium, Hium = hium, SupportingPower = calculateSupportingPower(production), Production = productionRange, Equipment = equipment, TowerHeight = h, Range = range }; return(result); }