/// <summary> /// Делаем расчет по формуле /// </summary> /// <param name="formulaId">Идентификатор формулы</param> /// <param name="inDataTI">Данные по ТИ</param> /// <param name="inDataIntegrals">Интегральные данные</param> /// <param name="inDataTP">Данные по ТП</param> /// <param name="inDataSection">Данные по сечению</param> /// <param name="indxStart">Начальный индекс, с которого формула активна</param> /// <param name="indxEnd">Конечный индекс</param> /// <param name="unitDigitCoeff">Коэфф. дорасчета ед. измерения</param> /// <param name="formulaTPType">Тип формулы ТП</param> /// <param name="formulasTable">Табличный тип формулы (обычная или ТП)</param> /// <param name="tpId">Идентификатор ТП к которой привязана формула</param> /// <param name="rangeInSectionForEntirePeriod">Используется ли формула в сечении, где действует ограничение на период действия ТП</param> /// <param name="rangeIndexesInSectionList">Индексы с которого действуют ТП в сечении</param> /// <param name="hiHiSetpoint">Верхняя уставка, по которой проверяем формулу</param> /// <param name="loLoSetpoint">Нижняя уставка, по которой проверяем формулу</param> /// <param name="inFormulaConstants">Данные по константам, используемым в формуле</param> /// <param name="formulasDisabledPeriods">Индексы получасовок между которыми формула не считается</param> /// <returns></returns> public List <TVALUES_DB> InterpretFormula(string formulaId , bool isSumm , int indxStart, int indxEnd, double unitDigitCoeff, enumClientFormulaTPType formulaTPType, enumFormulasTable formulasTable, bool rangeInSectionForEntirePeriod = true, IEnumerable <IPeriodIndexesTpInSection> rangeIndexesInSectionList = null, double?hiHiSetpoint = null, double?loLoSetpoint = null, IEnumerable <IFormulasDisabledPeriod> formulasDisabledPeriods = null, string measureUnitUn = null, PeriodFactory manualEnteredHalfHourIndexes = null) { var isCalculateBetweenIndexes = !InterpretatorParams.TechProfilePeriod.HasValue && (indxStart > 0 || indxEnd < (InterpretatorParams.NumbersHalfHours - 1)); var isExistDisablePeriod = formulasDisabledPeriods != null && formulasDisabledPeriods.ToList().Count > 0; _recursionCallStack.Clear(); double?coeff; if (string.IsNullOrEmpty(measureUnitUn)) { if (unitDigitCoeff > 1) { coeff = 1 / unitDigitCoeff; if (InterpretatorParams.TypeInformation == enumTypeInformation.Power) { coeff *= 2; } } else if (InterpretatorParams.TypeInformation == enumTypeInformation.Power) { coeff = 2; } else { coeff = null; } } else { coeff = null; } _formulasTable = formulasTable; var formula = GetFormulaByID(formulaId); var polskaParams = new PolskaParams(formula.F_ID, _formulasTable, InterpretatorParams.StartDateTime, InterpretatorParams.EndDateTime, InterpretatorParams.DiscreteType, InterpretatorParams.NumbersHalfHours, formula.UnitDigit, InterpretatorParams.TechProfilePeriod.HasValue); var parser = ComposeExpressionPolskaya(formula, polskaParams, indxStart, indxEnd, InterpretatorParams.NumbersHalfHours, isCalculateBetweenIndexes); parser.Compile(); //var result = new List<TVALUES_DB>(); using (var accamulator = new FormulaAccamulator(InterpretatorParams.IntervalTimeList, isSumm, formula.UnitDigit)) { //Считаем всегда по получасовкам for (var halfHourIndex = 0; halfHourIndex < InterpretatorParams.NumbersHalfHours; halfHourIndex++) { // рассчет по формуле if (!isCalculateBetweenIndexes || halfHourIndex >= indxStart && halfHourIndex <= indxEnd) { #region Ограничиваем диапазоном в сечении if (!rangeInSectionForEntirePeriod) { if (!rangeIndexesInSectionList.Any(range => range.StartIndex <= halfHourIndex && (range.FinishIndex ?? InterpretatorParams.NumbersHalfHours - 1) >= halfHourIndex)) { accamulator.Accamulate(0, VALUES_FLAG_DB.TpNotInSectionRange, enumClientFormulaTPType.TpNotInSectionRange); continue; } } #endregion #region Ограничиваем когда формула заблокирована напряму таблицей Info_Formula_DisabledPeriod if (isExistDisablePeriod) { if (formulasDisabledPeriods.Any(range => halfHourIndex >= range.StartIndx && halfHourIndex <= range.FinishIndx)) { accamulator.Accamulate(0, VALUES_FLAG_DB.FormulaNotInRange); //result.Add(new Formula_VALUES_DB(VALUES_FLAG_DB.FormulaNotInRange, 0)); continue; } } #endregion #region Ограничиваем периодами, когда данные были введены вручную (считать не нужно) if (manualEnteredHalfHourIndexes != null && manualEnteredHalfHourIndexes.HavePeriod(halfHourIndex)) { //result.Add(new Formula_VALUES_DB(VALUES_FLAG_DB.None, 0)); accamulator.Accamulate(0, VALUES_FLAG_DB.None); continue; } #endregion var val = parser.EvaluateStringValue(halfHourIndex); #region Обрабатываем уставки if (hiHiSetpoint.HasValue && val.F_VALUE >= hiHiSetpoint) { val.F_FLAG |= VALUES_FLAG_DB.HiHiSetpointExcess; } if (loLoSetpoint.HasValue && val.F_VALUE <= loLoSetpoint) { val.F_FLAG |= VALUES_FLAG_DB.LoLoSetpointExcess; } #endregion //Учитываем что это мощность или размерность (кило, мега и т.д.) if (coeff.HasValue) { val.F_VALUE *= coeff.Value; } val.FormulaTPType = formulaTPType; accamulator.Accamulate(val.F_VALUE, val.F_FLAG, formulaTPType); //result.Add(val.F_VALUE, val.F_FLAG); } else { accamulator.Accamulate(0, VALUES_FLAG_DB.FormulaNotInRange, enumClientFormulaTPType.NotInRange); //Ограничения по времени действия формулы //result.Add(new Formula_VALUES_DB(VALUES_FLAG_DB.FormulaNotInRange, 0, enumClientFormulaTPType.NotInRange)); } } return(accamulator.Result); } //return result; }
/// <summary> /// Набор расчетных параметров для обсчета формулы /// </summary> /// <param name="formulaParams"></param> /// <param name="resultTi"></param> /// <param name="resultIntegral"></param> /// <param name="resultTp"></param> /// <param name="resultSection"></param> public void BuildVariableParams(IFormulaParam formulaParams, string msTimeZoneId = null, bool isArchTech = false) { if (_recursionCallStack.Contains(formulaParams.FormulaID)) { throw new FormulaParseException("Обнаружена рекурсия формулы\n[" + GetOperNameFromDB(formulaParams.FormulaID, F_OPERATOR.F_OPERAND_TYPE.Formula, null) + "]"); } _recursionCallStack.Add(formulaParams.FormulaID); _formulasTable = formulaParams.FormulasTable; int?tpId = null; if (formulaParams.tP_CH_ID != null) { tpId = formulaParams.tP_CH_ID.TP_ID; } if (Archives == null) { Archives = new FormulaArchives(isArchTech, tpId); } //Часовой пояс в котором запрашиваем данные //var tz = (string.IsNullOrEmpty(msTimeZoneId) ? formulaParams.MsTimeZoneId : msTimeZoneId); var f = GetFormulaByID(formulaParams.FormulaID); if (f == null) { //Ф-ла не описана, либо не входит в наш диапазон _recursionCallStack.Remove(formulaParams.FormulaID); return; } foreach (var operators in f.F_OPERATORS) { var operIdInt = 0; if (string.IsNullOrEmpty(operators.OPER_ID)) { continue; } if (operators.OPER_TYPE != F_OPERATOR.F_OPERAND_TYPE.Formula && operators.OPER_TYPE != F_OPERATOR.F_OPERAND_TYPE.FormulaConstant) { if (int.TryParse(operators.OPER_ID, out operIdInt) == false) { throw new FormulaParseException("Идентификатор ТИ [" + operators.OPER_ID + "] должен быть целочисленным!"); } if (!operators.TI_CHANNEL.HasValue) { throw new FormulaParseException("В формуле не указан канал измерения!"); } } switch (operators.OPER_TYPE) { case F_OPERATOR.F_OPERAND_TYPE.UANode: Archives.FormulaUaNodeVariableDataTypeList.Add(new TUANodeDataId { UANodeId = operIdInt, DataType = (UANodeDataIdDataTypeEnum)operators.TI_CHANNEL.GetValueOrDefault() }); break; case F_OPERATOR.F_OPERAND_TYPE.Section: Archives.SectionSorted.Add(new TSectionChannel { Section_ID = operIdInt, ChannelType = operators.TI_CHANNEL.Value }); break; case F_OPERATOR.F_OPERAND_TYPE.TP_channel: HashSet <TP_ChanelType> tpChannelTypes; if (!Archives.TPChanelTypeList.TryGetValue(operIdInt, out tpChannelTypes) || tpChannelTypes == null) { Archives.TPChanelTypeList[operIdInt] = tpChannelTypes = new HashSet <TP_ChanelType>(new TP_ChanelComparer()); } tpChannelTypes.Add(new TP_ChanelType { TP_ID = operIdInt, ChannelType = operators.TI_CHANNEL.Value, ClosedPeriod_ID = formulaParams.ClosedPeriod_ID, }); break; case F_OPERATOR.F_OPERAND_TYPE.Integral_Channel: HashSet <TI_ChanelType> integralChannelTypes; if (!Archives.IntegralChanelTypeList.TryGetValue(operIdInt, out integralChannelTypes) || integralChannelTypes == null) { Archives.IntegralChanelTypeList[operIdInt] = integralChannelTypes = new HashSet <TI_ChanelType>(new ITI_ChanelComparer()); } integralChannelTypes.Add(new TI_ChanelType { TI_ID = operIdInt, ChannelType = operators.TI_CHANNEL.Value, IsCA = operators.OPER_TYPE == F_OPERATOR.F_OPERAND_TYPE.ContrTI_Chanel, TP_ID = tpId, DataSourceType = InterpretatorParams.DataSourceType, ClosedPeriod_ID = formulaParams.ClosedPeriod_ID, //MsTimeZone = tz, }); break; case F_OPERATOR.F_OPERAND_TYPE.ContrTI_Chanel: case F_OPERATOR.F_OPERAND_TYPE.TI_channel: HashSet <TI_ChanelType> tiChannelTypes; if (!Archives.TIChanelTypeList.TryGetValue(operIdInt, out tiChannelTypes) || tiChannelTypes == null) { Archives.TIChanelTypeList[operIdInt] = tiChannelTypes = new HashSet <TI_ChanelType>(new ITI_ChanelComparer()); } tiChannelTypes.Add(new TI_ChanelType { TI_ID = operIdInt, ChannelType = operators.TI_CHANNEL.Value, IsCA = operators.OPER_TYPE == F_OPERATOR.F_OPERAND_TYPE.ContrTI_Chanel, TP_ID = tpId, DataSourceType = InterpretatorParams.DataSourceType, ClosedPeriod_ID = formulaParams.ClosedPeriod_ID, //MsTimeZone = tz, }); break; case F_OPERATOR.F_OPERAND_TYPE.FormulaConstant: Archives.FormulaConstantIds.Add(operators.OPER_ID); break; case F_OPERATOR.F_OPERAND_TYPE.Formula: IFormulaParam fId = new FormulaParam { FormulaID = operators.OPER_ID, FormulasTable = _formulasTable, tP_CH_ID = formulaParams.tP_CH_ID, MsTimeZoneId = formulaParams.MsTimeZoneId }; //Собираем переменные из вложенной формулы BuildVariableParams(fId, msTimeZoneId); break; } } _recursionCallStack.Remove(formulaParams.FormulaID); }