Esempio n. 1
0
        /// <summary>
        /// 构建拓朴图
        /// </summary>
        /// <param name="calculateName">计算名称</param>
        /// <param name="graph">拓朴图</param>
        /// <param name="date">数据的日期,有可能不同日期的公式所引用的测点不一样</param>
        private void constructGraph(string calculateName, ALGraph.MyGraph graph, DateTimeOffset date)
        {
            hammergo.caculator.MyList list = getChildApp(calculateName, date);

            for (int i = 0; i < list.Length; i++)
            {
                string calcSn = list.getKey(i);
                graph.addArcNode(new ALGraph.ArcNode(), calculateName, calcSn);


                constructGraph(calcSn, graph, date);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// 获取仪器的子仪器数据
        /// </summary>
        /// <param name="calculateName"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private hammergo.caculator.MyList getChildApp(string calculateName, DateTimeOffset date)
        {
            hammergo.caculator.MyList list = new hammergo.caculator.MyList(5);

            List <string> calcNameList = DbContext.GetChildAppCalcName(calculateName, date).ToList();

            foreach (string name in calcNameList)
            {
                list.add(name, 0);
            }


            return(list);
        }
Esempio n. 3
0
        /// <summary>
        ///  根据计算公式搜索引用该测点的所有子测点
        /// </summary>
        /// <param name="parentApp">父测点</param>
        /// <returns></returns>
        private List <App> getChildApp(App parentApp)
        {
            hammergo.caculator.MyList list = new hammergo.caculator.MyList(5);



            //需要考虑各时间段的不同
            var ids = (from i in dbcontext.Formulae
                       where i.FormulaExpression.Contains(parentApp.CalculateName + ".")
                       select i.ParamId).Distinct();

            //同一个子测点的计算公式可能多次引用父测点的计算编号
            var children = (from i in dbcontext.Apps
                            join p in dbcontext.CalculateParams
                            on i.Id equals p.Id
                            join calcID in ids
                            on p.Id equals calcID
                            select i).AsNoTracking().Distinct().ToList();

            return(children);
        }
Esempio n. 4
0
        /// <summary>
        /// 将实际的值填充到参数列表中,如果参数没有相应的值,将被赋初值0
        /// </summary>
        /// <param name="list">参数列表</param>
        /// <param name="appCalcName">测点的计算名称</param>
        /// <param name="date">日期</param>
        /// <param name="appendDot">是否将计算名称和点加在参数的前面</param>
        /// <param name="simpleInfo">测点数据信息</param>
        internal static void fillListByCalcName_Date(hammergo.caculator.MyList list, DateTimeOffset date, bool appendDot, AppIntegratedInfo simpleInfo)
        {
            string appCalcName = simpleInfo.CurrentApp.CalculateName;

            foreach (ConstantParam cp in simpleInfo.ConstantParams)
            {
                string key = cp.ParamSymbol;
                if (appendDot)
                {
                    key = String.Format("{0}.{1}", appCalcName, key);
                }
                list.add(key, cp.Val);
            }

            //赋初值0

            foreach (MessureParam mp in simpleInfo.MesParams)
            {
                string key = mp.ParamSymbol;
                if (appendDot)
                {
                    key = String.Format("{0}.{1}", appCalcName, key);
                }
                list.add(key, 0);
            }

            //赋初值0
            foreach (CalculateParam cp in simpleInfo.CalcParams)
            {
                string key = cp.ParamSymbol;
                if (appendDot)
                {
                    key = String.Format("{0}.{1}", appCalcName, key);
                }
                list.add(key, 0);
            }

            //加快速度
            foreach (MessureValue mv in simpleInfo.MesValues.Where(s => s.Date == date))
            {
                MessureParam mp = simpleInfo.MesParams.Find(delegate(MessureParam item) { return(item.Id == mv.ParamId); });

                string key = mp.ParamSymbol;
                if (appendDot)
                {
                    key = String.Format("{0}.{1}", appCalcName, key);
                }

                list[key] = mv.Val.Value;
            }

            //加快速度
            foreach (CalculateValue cv in simpleInfo.CalcValues.Where(s => s.Date == date))
            {
                CalculateParam cp  = simpleInfo.CalcParams.Find(delegate(CalculateParam item) { return(item.Id == cv.ParamId); });
                string         key = cp.ParamSymbol;
                if (appendDot)
                {
                    key = String.Format("{0}.{1}", appCalcName, key);
                }

                list[key] = cv.Val.Value;
            }
        }
Esempio n. 5
0
        /// <summary>
        /// 由于messure values更改了,需要重新计算calc values的值
        /// </summary>
        /// <param name="appInfo"></param>
        /// <param name="currentRow"></param>
        /// <param name="date"></param>
        internal static void reCalcValues(AppIntegratedInfo appInfo, DataRow currentRow, DateTimeOffset date)
        {
            hammergo.caculator.CalcFunction calc = new hammergo.caculator.CalcFunction();
            hammergo.caculator.MyList       list = new hammergo.caculator.MyList();

            //填充自身,要求在appInfo中的数据是更新后的数据
            fillListByCalcName_Date(list, date, false, appInfo);

            //分析此仪器是否引用了其它仪器的数据
            hammergo.caculator.MyList appCalcNameList = new hammergo.caculator.MyList();//引用的其它仪器名称的集合

            var sortedParams = new SortedDictionary <byte, ParamHelper>();



            //这里必须按照calc order 的顺序
            foreach (CalculateParam cp in appInfo.CalcParams)
            {
                Formula formulaEntity = appInfo.AllFormulae.SingleOrDefault(s => s.ParamId == cp.Id && s.StartDate <= date && date < s.EndDate);

                if (formulaEntity == null)
                {
                    throw new Exception(string.Format("找不到对应时间:{0:u}的工式,请检查测点的参数信息", date));
                }

                sortedParams.Add(formulaEntity.CalculateOrder, new ParamHelper {
                    FormulaEntity = formulaEntity, Param = cp
                });

                string formulaString = formulaEntity.FormulaExpression;//获取表达式

                System.Collections.ArrayList vars = calc.getVaribles(formulaString);
                //为了避免对某个测点的数据重复查询,将一次性填充一支仪器的数据


                for (int j = 0; j < vars.Count; j++)
                {
                    string vs  = (string)vars[j];
                    int    pos = vs.IndexOf('.');
                    if (pos != -1)
                    {
                        //引用了其它测点
                        string otherID = vs.Substring(0, pos);
                        appCalcNameList.add(otherID, 0);
                        //避免由于计算时依赖其它仪器,而其它仪器没有此刻的记录时,导致异常
                        list.add(vs, 0);
                    }
                }
            }

            //填充带点的参数
            for (int i = 0; i < appCalcNameList.Length; i++)
            {
                AppIntegratedInfo simpleAppInfo = new AppIntegratedInfo(appCalcNameList.getKey(i), date);
                fillListByCalcName_Date(list, date, true, simpleAppInfo);
            }

            //可以进行表达式求值了

            //根据计算顺序
            for (int i = 0; i < sortedParams.Count; i++)
            {
                var helperobj = sortedParams.ElementAt(i).Value;
                var cp        = helperobj.Param;
                //顺序是以order 升序排列
                string formula = helperobj.FormulaEntity.FormulaExpression;//获取表达式

                double v = calc.compute(formula, list);

                byte precision = cp.PrecisionNum;

                if (precision >= 0)
                {
                    v = Helper.Round(v, precision);
                }



                CalculateValue calcValue = appInfo.CalcValues.Find(delegate(CalculateValue item)
                {
                    return(item.Date == date && item.ParamId == cp.Id);
                });

                if (calcValue == null)
                {
                    //create new object
                    calcValue         = new CalculateValue();
                    calcValue.Date    = date;
                    calcValue.ParamId = cp.Id;

                    appInfo.CalcValues.Add(calcValue);

                    //添加到dbcontext中
                    appInfo.DbContext.AddToCalculateValues(calcValue);
                }

                calcValue.Val = v;

                appInfo.DbContext.UpdateObject(calcValue);

                //在填充时已添加,这里就不能添加
                list[cp.ParamSymbol] = v;

                if (currentRow != null)
                {
                    currentRow[cp.ParamName] = v;
                }
            }
        }
Esempio n. 6
0
        public void Validate()
        {
            List <string> nameList   = new List <string>(20);
            List <string> symbolList = new List <string>(20);

            //_modifiedApp _modifiedParams和实例中的其它Entity属于不同的dbcontext

            //需要验证公式更新的逻辑,这是整个app最复杂的问题之一,其它有公式解析和拓扑排序
            //获取参数列表
            var paramsLocal = (from i in dbcontext.AppParams
                               where i.AppId == _modifiedApp.Id
                               select i).AsNoTracking().ToList();
            //获取该测点的所有计算公式

            //当前数据库中的参数列表
            var formulaeLocal = (from p in dbcontext.AppParams.OfType <CalculateParam>()
                                 where p.AppId == _modifiedApp.Id
                                 join f in dbcontext.Formulae
                                 on p.Id equals f.ParamId
                                 select f).ToList(); //需要更新formula的计算次序


            //处理added,modified,deleted
            //用修改的值替换内存中的值
            foreach (var entry in _paramsEntries)
            {
                var entity = entry.Entity as AppParam;
                if (entity.AppId == _modifiedApp.Id)
                {
                    //只能是modified或deleted
                    int index = paramsLocal.FindIndex(s => s.Id == entity.Id);
                    if (index >= 0)
                    {
                        paramsLocal.RemoveAt(index);
                    }
                    if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
                    {
                        paramsLocal.Add(entity);
                    }
                    else if (entry.State == EntityState.Deleted)
                    {
                        //在删除参数时,会级联删除公式

                        formulaeLocal.RemoveAll(s => s.ParamId == entity.Id);
                    }
                }
            }

            foreach (ObjectStateEntry entry in _formulaEntries)
            {
                var entity = entry.Entity as Formula;
                //公式必须依附于参数
                //paramList中的参数有可以是新增的参数,即数据库还没有记录
                if (paramsLocal.Exists(s => s.Id == entity.ParamId))
                {
                    int index = formulaeLocal.FindIndex(s => s.ParamId == entity.ParamId && s.StartDate == entity.StartDate);
                    if (index >= 0)
                    {
                        //entity已被修改,或增加,删除,得先从列表中先先移除
                        formulaeLocal.RemoveAt(index);
                    }
                    if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
                    {
                        formulaeLocal.Add(entity);
                    }
                }
            }


            //检查名称和符号是否有重复
            checkParamNames(paramsLocal, nameList, symbolList);

            //测点公式的时间段必须具备连续性,所以需先对公式进行检查
            var formulaGroup = (from i in formulaeLocal
                                orderby i.StartDate ascending
                                group i by i.StartDate).ToList();
            int gCnt = formulaGroup.Count();

            if (gCnt > 0)
            {
                int calcParamsCnt = paramsLocal.OfType <CalculateParam>().Count();

                //每组公式的结束时间
                DateTimeOffset?endDate = null;;
                for (int i = 0; i < gCnt; i++)
                {
                    var item      = formulaGroup[i];
                    var startDate = item.Key;
                    if (endDate != null)
                    {
                        if (startDate != endDate)
                        {
                            throw new Exception(string.Format("起始时间为{0}的公式的开始时间与上一分段公式的结束时间没有衔接,\n即上一段公式的结束时间必须是下一段公式的开始时间", startDate));
                        }
                    }

                    //检查个数

                    if (item.Count() != calcParamsCnt)
                    {
                        throw new Exception(string.Format("起始时间为{0}的公式与计算参数的数目不一致", startDate));
                    }

                    //公式和参数要一一对应,检查对应关系
                    var compositList = (from ci in paramsLocal.OfType <CalculateParam>()
                                        join f in item.AsEnumerable()
                                        on ci.Id equals f.ParamId
                                        select new
                    {
                        Param = ci,
                        Formula = f
                    }).ToList();
                    if (compositList.Count != calcParamsCnt)
                    {
                        throw new Exception(string.Format("起始时间为{0}的公式没有与计算参数一一对应", startDate));
                    }


                    endDate = item.ElementAt(0).EndDate;

                    if (startDate >= endDate)
                    {
                        throw new Exception("分段公式的开始时间必须小于结束时间");
                    }

                    if (item.Count(s => s.EndDate == endDate) != calcParamsCnt)
                    {
                        throw new Exception(string.Format("起始时间为{0}的公式结束时间不一致", startDate));
                    }

                    //检查每组公式的计算逻辑

                    hammergo.caculator.MyList list = new hammergo.caculator.MyList(10);

                    int num = 1;//填充一些数据,测试计算的表达式
                    foreach (string s in symbolList)
                    {
                        list.add(s, num++);
                    }



                    // 简单的判断公式的依赖关系,只能精确到仪器,不能精确的量(如n01cf14.e的依赖关系,过于复杂)


                    //生成新的图
                    ALGraph.MyGraph graph = new ALGraph.MyGraph();
                    hammergo.caculator.CalcFunction calc = new hammergo.caculator.CalcFunction();
                    //引用测点的编号列表
                    hammergo.caculator.MyList calcNameList = new hammergo.caculator.MyList(5);



                    foreach (var cp in compositList)
                    {
                        string formulaString = cp.Formula.FormulaExpression;
                        string symbol        = cp.Param.ParamSymbol;

                        if (formulaString == null || formulaString.Trim().Length == 0)
                        {
                            throw new Exception(string.Format("计算参数 {0} 的计算公式不能为空", cp.Param.ParamName));
                        }

                        ArrayList vars = calc.getVaribles(formulaString);

                        intitalVars(_modifiedApp.CalculateName, vars, graph, calcNameList, symbol);
                    }


                    ArrayList toplist = graph.topSort();
                    if (toplist.Count != graph.Vexnum)
                    {
                        throw new Exception("公式存在循环依赖");
                    }

                    ArrayList storeTopList = toplist;

                    // 刚才是检查仪器内的循环依赖,现在和所有的仪器一起检查


                    graph = new ALGraph.MyGraph();

                    for (int j = 0; j < calcNameList.Length; j++)
                    {
                        graph.addArcNode(new ALGraph.ArcNode(), calcNameList.getKey(j), _modifiedApp.CalculateName); //全部使用计算名称
                        var loopCheckList = new List <Guid>(5);
                        constructGraph(_modifiedApp, graph, loopCheckList);                                          //递归加入其子结点
                    }

                    toplist = graph.topSort();
                    if (toplist.Count != graph.Vexnum)
                    {
                        System.Text.StringBuilder sb = new System.Text.StringBuilder(128);
                        foreach (ALGraph.VNode node in graph.vertices)
                        {
                            sb.Append(node.data).Append("  ");
                        }
                        throw new Exception(sb.ToString() + " 仪器公式存在循环依赖");
                    }


                    toplist = storeTopList;

                    //图不存在回路
                    //引用的其它测点,填充
                    for (int j = 0; j < calcNameList.Length; j++)
                    {
                        string calcName = calcNameList.getKey(j);

                        var refApp = dbcontext.Apps.AsNoTracking().FirstOrDefault(s => s.CalculateName == calcName);

                        if (refApp == null)
                        {
                            throw new Exception(string.Format("计算名称为{0}的仪器不存在!", calcName));
                        }
                        //ArrayList paList = new ArrayList(12);
                        //paList.AddRange(consBLL.GetListByappName(refApp.AppName));
                        //paList.AddRange(mesBLL.GetListByappName(refApp.AppName));
                        //paList.AddRange(calcBLL.GetListByappName(refApp.AppName));

                        var paList = refApp.AppParams.ToList();

                        for (int k = 0; k < paList.Count; k++)
                        {
                            var pi = paList[k];

                            list.add(calcName + "." + pi.ParamSymbol, k + 1);
                        }
                    }


                    foreach (var cp in compositList)
                    {
                        string formula = cp.Formula.FormulaExpression;
                        calc.compute(formula, list);

                        string symbol = cp.Param.ParamSymbol;

                        int index = toplist.IndexOf(symbol);
                        if (index < 0)
                        {
                            //此符号不在拓扑图中,没有公式依赖于它
                            index = toplist.Count;
                        }

                        //cp.CalculateOrder = (byte)index;
                        //更新计算次序
                        cp.Formula.CalculateOrder = (byte)index;
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// 构造树型结点,并查找计算变量引用的测点
        /// </summary>
        /// <param name="appCalcName">计算名称</param>
        /// <param name="vars">计算公式中需要的计算变量</param>
        /// <param name="graph">拓扑树</param>
        /// <param name="idList">引用测点计算的计算名称列表</param>
        /// <param name="symbol">当前计算量的符号</param>
        private void intitalVars(string appCalcName, ArrayList vars, ALGraph.MyGraph graph, hammergo.caculator.MyList idList, string symbol)
        {
            for (int i = 0; i < vars.Count; i++)
            {
                string vs  = (string)vars[i];
                int    pos = vs.IndexOf('.');
                if (pos != -1)//带点的参数
                {
                    string otherID = vs.Substring(0, pos);
                    if (otherID == appCalcName)//计算名称
                    {
                        throw new Exception("公式中的变量不能包含本仪器的二级变量");
                    }
                    else
                    {
                        idList.add(otherID.ToUpper(), 0);
                    }
                }
                else
                {
                    //					//不带点的参数

                    //添加弧

                    graph.addArcNode(new ALGraph.ArcNode(), vs, symbol);
                }
            }
        }