/// <summary> /// Проверяем входит ли период действия текущего объекта в указанную получасоку получасовка /// Если не входит, то выбираем следующий объект, который входит /// </summary> /// <param name="period"></param> /// <param name="periods"></param> /// <param name="hh"></param> /// <param name="resultCommonTi"></param> /// <returns></returns> private static bool PeriodInHalfHour(ref PeriodHierarchy period, Queue <PeriodHierarchy> periods, int hh, ArchivesValues_List2 resultCommonTi, FormulasResult resultCommonFormula, ArchivesTPValues resultCommonTp, UADataReader resultCommonUAData) { if (period == null) { if (periods.Count == 0) { return(false); } period = periods.Dequeue(); } bool inHalfHour; if (period != null && !period.IsFullPeriod) { if (period.IndxStart.HasValue && period.IndxStart > hh) { //Этоn период еще не начался return(false); } if (period.IndxFinish.HasValue && period.IndxFinish < hh) { //У этого периода кончилось действие period = null; inHalfHour = PeriodInHalfHour(ref period, periods, hh, resultCommonTi, resultCommonFormula, resultCommonTp, resultCommonUAData); } else { inHalfHour = true; } } else { inHalfHour = true; } if (period == null) { return(false); } #region Наполняем архив if (period.Archives == null) { var id = period.Id; switch (id.TypeHierarchy) { case enumTypeHierarchy.Info_TI: int tiId; List <TArchivesValue> tiValues; if (int.TryParse(id.ID, out tiId) && resultCommonTi.ArchiveValues.TryGetValue(tiId, out tiValues)) { var archiveTi = tiValues .FirstOrDefault(v => v.TI_Ch_ID.TI_ID == tiId && v.TI_Ch_ID.ChannelType == id.Channel); if (archiveTi != null) { period.Archives = archiveTi.Val_List; } } break; case enumTypeHierarchy.Formula: var archiveFormula = resultCommonFormula.Result_Values .FirstOrDefault(v => string.Equals(v.Formula_UN, id.ID)); if (archiveFormula != null && archiveFormula.Result_Values != null && archiveFormula.Result_Values.Count > 0) { var vals = archiveFormula.Result_Values[0].Val_List; if (vals != null) { period.Archives = vals.OfType <TVALUES_DB>().ToList(); } } break; case enumTypeHierarchy.Info_TP: int tpId; if (int.TryParse(id.ID, out tpId)) { var archiveTp = resultCommonTp.ArchivesValue30orHour .FirstOrDefault(v => v.TpIdChannel.TP_ID == tpId && v.TpIdChannel.ChannelType == id.Channel); if (archiveTp != null) { //archiveTp.Val_List.TryGetValue(archiveTp.IsMoneyOurSide, out period.Archives); period.Archives = archiveTp.GetValues(); } } break; case enumTypeHierarchy.Node: var archiveNode = resultCommonUAData.UADatas .FirstOrDefault(v => string.Equals(v.UANode_ID, id.ID)); if (archiveNode != null) { //TODO тут непонятно //archiveTp.Val_List.TryGetValue(archiveTp.IsMoneyOurSide, out period.Archives); //period.Archives = archiveNode.GetValues(); } break; } } #endregion return(inHalfHour); }
/// <summary> /// Берем первую попавшуюся модель прогнозирования для объекта /// </summary> /// <param name="forecastObjectUn"></param> /// <returns></returns> public static List <TForecastCalculateParams> GetForecastObjectParams(HashSet <string> forecastObjectUns, DateTime dtStart, DateTime dtEnd, int?forecastModelUserSelected, string timeZoneId, StringBuilder errors, EnumUnitDigit unitDigit, enumTimeDiscreteType forecastDiscreteType, bool isReadCalculatedValues) { var tis = new List <TI_ChanelType>(); var formulas = new List <TFormulaParam>(); var tps = new List <TP_ChanelType>(); var nodes = new List <long>(); var result = new Dictionary <string, TForecastCalculateParams>(); var periodsPriorityByForecastObject = new Dictionary <string, Dictionary <string, Queue <PeriodHierarchy> > >(); if (forecastObjectUns == null) { return(result.Values.ToList()); } #region Читаем параметры объектов прогнозирования из базы var forecastObjectUnsString = string.Join(",", forecastObjectUns); try { using (var db = new LightDBDataContext(Settings.DbConnectionString) { ObjectTrackingEnabled = false, //Указываем что это у нас ReadOnly DeferredLoadingEnabled = false, CommandTimeout = 180, }) { var multiResult = db.usp2_ForecastObjectParams(forecastObjectUnsString, dtStart.ClientToServer(timeZoneId), dtEnd.ClientToServer(timeZoneId)); //Читаем доступные модели, которым будем считать foreach (var modelsGroupByObject in multiResult.GetResult <usp2_ForecastObjectParamsResult1>().ToList().GroupBy(g => g.ForecastObject_UN)) { result[modelsGroupByObject.Key] = new TForecastCalculateParams(modelsGroupByObject.Key, forecastModelUserSelected, new HashSet <int>(modelsGroupByObject.Where(m => m.ForecastCalculateModel_ID.HasValue).OrderBy(m => m.Priority ?? 1000).Select(m => (int)(m.ForecastCalculateModel_ID ?? 0)))); } #region Читаем ТИ, ТП формулы и т.д. для обсчета foreach (var inputParamByObject in multiResult.GetResult <usp2_ForecastObjectParamsResult2>().ToList().GroupBy(g => g.ForecastObject_UN)) { TForecastCalculateParams calculateParams; if (!result.TryGetValue(inputParamByObject.Key, out calculateParams) || calculateParams == null) { continue; } calculateParams.DtStart = dtStart; calculateParams.DtEnd = dtEnd; calculateParams.DiscreteType = forecastDiscreteType; var periodsByInputParam = new Dictionary <string, Queue <PeriodHierarchy> >(); periodsPriorityByForecastObject[inputParamByObject.Key] = periodsByInputParam; foreach (var inputParam in inputParamByObject.GroupBy(g => g.ForecastInputParam_UN)) { var periods = new Queue <PeriodHierarchy>(); periodsByInputParam[inputParam.Key] = periods; var archiveByInputParam = new ForecastByInputParamArchives(inputParam.Key); calculateParams.ArchivesByInputParam.Add(archiveByInputParam); var isFirst = true; foreach (var physicalParam in inputParam) { bool isFullPeriod; var period = BuildHalfHoursPeriods(physicalParam, dtStart, dtEnd, timeZoneId, out isFullPeriod); if (isFirst) { archiveByInputParam.MeasureQuantityType_UN = physicalParam.MeasureQuantityType_UN; isFirst = false; } //Формула if (!string.IsNullOrEmpty(physicalParam.Formula_UN)) { var formulaParam = new TFormulaParam { FormulaID = physicalParam.Formula_UN, FormulasTable = enumFormulasTable.Info_Formula_Description, IsFormulaHasCorrectDescription = true, }; formulas.Add(formulaParam); //archiveByInputParam.Formulas.Add(formulaParam); periods.Enqueue(new PeriodHierarchy { Id = new ID_Hierarchy_Channel(enumTypeHierarchy.Formula, physicalParam.Formula_UN, 0), IsFullPeriod = isFullPeriod, IndxStart = period.Item1, IndxFinish = period.Item2, }); if (isFullPeriod) { continue; //Объект действует на весь период, остальные объекты пропускаем } } //OPC пока не используется, т.к. не понятно как приводить к получасовкам if (physicalParam.UANode_ID.HasValue) { //archiveByInputParam.Nodes.Add(physicalParam.UANode_ID.Value); nodes.Add(physicalParam.UANode_ID.Value); periods.Enqueue(new PeriodHierarchy { Id = new ID_Hierarchy_Channel(enumTypeHierarchy.UANode, physicalParam.UANode_ID.Value.ToString(), 0), IsFullPeriod = isFullPeriod, IndxStart = period.Item1, IndxFinish = period.Item2, }); if (isFullPeriod) { continue; //Объект действует на весь период, остальные объекты пропускаем } } //Для остальных нужен канал, если не указан пропускаем //if (!inputParam.ChannelType.HasValue) continue; //ТИ if (physicalParam.TI_ID.HasValue) { if (!physicalParam.ChannelType.HasValue) { errors.Append("Для ТИ {").Append(physicalParam.TI_ID).Append("} нужно указать канал"); continue; } var tiId = new TI_ChanelType { ChannelType = physicalParam.ChannelType.Value, TI_ID = physicalParam.TI_ID.Value, MsTimeZone = timeZoneId, //Это возможно не нужно }; //archiveByInputParam.TiIds.Add(tiId); tis.Add(tiId); periods.Enqueue(new PeriodHierarchy { Id = new ID_Hierarchy_Channel(enumTypeHierarchy.Info_TI, physicalParam.TI_ID.Value.ToString(), physicalParam.ChannelType.Value), IsFullPeriod = isFullPeriod, IndxStart = period.Item1, IndxFinish = period.Item2, }); if (isFullPeriod) { continue; //Объект действует на весь период, остальные объекты пропускаем } } //ТП if (physicalParam.TP_ID.HasValue) { if (!physicalParam.ChannelType.HasValue) { errors.Append("Для ТП {").Append(physicalParam.TP_ID).Append("} нужно указать канал"); continue; } var tpId = new TP_ChanelType { ChannelType = physicalParam.ChannelType.Value, TP_ID = physicalParam.TP_ID.Value, }; //archiveByInputParam.TpIds.Add(tpId); tps.Add(tpId); periods.Enqueue(new PeriodHierarchy { Id = new ID_Hierarchy_Channel(enumTypeHierarchy.Info_TP, physicalParam.TP_ID.Value.ToString(), physicalParam.ChannelType.Value), IsFullPeriod = isFullPeriod, IndxStart = period.Item1, IndxFinish = period.Item2, }); } } } } #endregion } } catch (Exception ex) { errors.Append(ex.Message); } #endregion #region Читаем архивы //Пока запрашиваем только получасовки var resultCommonTi = new ArchivesValues_List2(tis, dtStart, dtEnd, true, false, enumTimeDiscreteType.DBHalfHours, enumTypeInformation.Energy, false, unitDigit, enumOVMode.NormalMode, timeZoneId, isReadCalculatedValues: isReadCalculatedValues); if (resultCommonTi.Errors != null) { errors.Append(resultCommonTi.Errors); } //Запрос значений всех ТП var resultCommonTp = new ArchivesTPValues(tps, dtStart, dtEnd, enumBusRelation.PPI_OurSide, enumTimeDiscreteType.DBHalfHours, null, enumTypeInformation.Energy, unitDigit, timeZoneId, false, isSupressTpNotFound: true, isReadCalculatedValues: isReadCalculatedValues); if (resultCommonTp.Errors != null) { errors.Append(resultCommonTp.Errors); } //Все формулы var resultCommonFormula = new FormulasResult(formulas, dtStart, dtEnd, enumTimeDiscreteType.DBHalfHours, null, 0, enumTypeInformation.Energy, unitDigit, timeZoneId, //Для описанных здесь формул ед. изм. не учитываем true, false, false, false, isReadCalculatedValues: isReadCalculatedValues, ovMode: enumOVMode.NormalMode); //Для формулы сумму с ОВ считаем всегда!!! if (resultCommonFormula.Errors != null) { errors.Append(resultCommonFormula.Errors); } //Чтение архивов OPC UADataReader resultCommonUAData = null; try { resultCommonUAData = new UADataReader(nodes, dtStart, dtEnd, false, false, false, timeZoneId); } catch { } #endregion #region Подготовка архивов var numberHalfHoursForForecasting = MyListConverters.GetNumbersValuesInPeriod(enumTimeDiscreteType.DBHalfHours, dtStart, dtEnd, timeZoneId); result.Values.AsParallel().ForAll(calculateParam => //AsParallel().ForAll() { //new TVALUES_DB[numberHalfHoursForForecasting].Select(v => new TVALUES_DB(VALUES_FLAG_DB.IsNull, 0)).ToList(); Dictionary <string, Queue <PeriodHierarchy> > periodsByInputParam; if (!periodsPriorityByForecastObject.TryGetValue(calculateParam.ForecastObject_UN, out periodsByInputParam) || periodsByInputParam.Count == 0) { return; //Нет параметров для обсчета } foreach (var paramArchives in calculateParam.ArchivesByInputParam) { Queue <PeriodHierarchy> periods; if (!periodsByInputParam.TryGetValue(paramArchives.ForecastInputParamUn, out periods) || periods.Count == 0) { continue; //Нет параметров для обсчета } //var period = periods.Dequeue(); //Первый объект в интервале PeriodHierarchy period = null; var halfHours = new List <TVALUES_DB>(); for (var hh = 0; hh < numberHalfHoursForForecasting; hh++) { if (!PeriodInHalfHour(ref period, periods, hh, resultCommonTi, resultCommonFormula, resultCommonTp, resultCommonUAData) || period.Archives == null) { halfHours.Add(new Servers.Calculation.DBAccess.Interface.Data.TVALUES_DB(VALUES_FLAG_DB.IsNull, 0)); //Получасовка не входит в наш диапазон, или нет архива continue; } var aVal = period.Archives.ElementAtOrDefault(hh); if (aVal == null) { aVal = new Servers.Calculation.DBAccess.Interface.Data.TVALUES_DB(VALUES_FLAG_DB.IsNull, 0); //Непонятная ситуация, помечаем как отсутствующие } var cVal = halfHours.ElementAtOrDefault(hh); if (cVal == null) { cVal = new Servers.Calculation.DBAccess.Interface.Data.TVALUES_DB(aVal.F_FLAG, aVal.F_VALUE); halfHours.Add(cVal); } else { cVal.F_VALUE = aVal.F_VALUE; cVal.F_FLAG = aVal.F_FLAG; } } paramArchives.Archives.AddRange(MyListConverters.ConvertHalfHoursToOtherList(forecastDiscreteType, halfHours, dtStart, dtEnd, timeZoneId).Select(v => new Servers.Calculation.DBAccess.Interface.Data.TVALUES_DB(v.F_FLAG, v.F_VALUE))); } }); #endregion return(result.Values.ToList()); }