using GDNXFD.Data; using GDNXFD.Data.Model; using GDNXFD.Data.Repositories; using GDNXFD.WcfService.RealtimeState.Domain; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; using WisdomClient.data; namespace GDNXFD.WcfService.RealtimeState { public class CalcStateSvc { //key 风机型号,value 不可复位的报警id集合 Dictionary> unAbleResetWarningDic = new Dictionary>(); //最小切入风速 启停计算 根据当前状态和风速 与最小切入风进行比较, 待机状态,大于切入风,则推荐启动,并网状态,小于切入风,则推荐停机 public Dictionary inputSpeedDic; // 配置文件的风速(低于这个值则表示接近于无风) double thereIsNoWind = Convert.ToDouble(ConfigurationManager.AppSettings["ThereIsNoWind"]); // 配置文件的风速(高于这个值则表示接近于有风,扇叶能够转起来) double theWindIsComing = Convert.ToDouble(ConfigurationManager.AppSettings["TheWindIsComing"]); // double thereIsSuperWind=Convert.ToDouble(ConfigurationManager.AppSettings["ThereIsSuperWind"]); // double thereIsAlmostNoWind = Convert.ToDouble(ConfigurationManager.AppSettings["ThereIsAlmostNoWind"]); // double thereIsAlmostNoPower = Convert.ToDouble(ConfigurationManager.AppSettings["ThereIsAlmostNoPower"]); // double maintainLowTemperature = Convert.ToDouble(ConfigurationManager.AppSettings["MaintainLowTemperature"]); // double unMaintainLowTemperature = Convert.ToDouble(ConfigurationManager.AppSettings["UnMaintainLowTemperature"]); #region 单例模式 private CalcStateSvc() { } public static CalcStateSvc Instance { get { return SingletonCreator.instance; } } class SingletonCreator { internal static readonly CalcStateSvc instance = new CalcStateSvc(); } #endregion private void createWarningDictionary() { if (unAbleResetWarningDic.Count <= 0) { try { var lst = FaultSnapRepository.getUnabledResetWarning(); if (lst != null && lst.Count > 0) { foreach (Warning warn in lst) { string key = warn.ModelId; long value = warn.EDnaValue; if (unAbleResetWarningDic.ContainsKey(key)) { HashSet vals = unAbleResetWarningDic[key]; if (vals.Contains(value) == false) vals.Add(value); } else { HashSet vals = new HashSet(); vals.Add(value); unAbleResetWarningDic.Add(key, vals); } } } } catch { } } } WStatus[] windturbineRunStatueArray = { WStatus.Online, WStatus.OnPower, WStatus.Start }; public void CalcWindturbine() { if (unAbleResetWarningDic.Count <= 0) createWarningDictionary(); IList resetList = new List(); IList stopList = new List(); IList startList = new List(); #region 计算需要复位的风机 using (GDNXFDDbContext ctx = new GDNXFDDbContext()) { IList faultWindturbineIdList = ctx.FaultSnap.Where(s => s.Category1 == "FJ" && s.IsOpened == true && s.StationId.Contains("_FDC") && !s.StationId.Contains("QS")).ToList().Select(s => s.WindturbineId).ToList(); DateTime time = DateTime.Now.AddDays(-3); IList alertSnap = ctx.AlertSnap.Where(s => faultWindturbineIdList.Contains(s.WindturbineId) && s.Category1 == "windturbine" && s.IsOpened == true && s.LastUpdateTime > time).ToList(); for (int i = 0; i < alertSnap.Count; i++) { bool allowReset = true; if(alertSnap[i].ModelId.IndexOf("105")>0) { continue; } //unAbleResetWarningDic 只包含1.5MW机型,若报警风机为2MW则默认风机可以进行复位 if (unAbleResetWarningDic.ContainsKey(alertSnap[i].ModelId)) { HashSet vals = unAbleResetWarningDic[alertSnap[i].ModelId]; if (vals != null && vals.Count > 0 && vals.Contains(alertSnap[i].AlertValue)) { allowReset = false; } if (allowReset) { AdviceModel m = new AdviceModel(); m.WindturbineId = alertSnap[i].WindturbineId; m.StationId = alertSnap[i].StationId; m.ModelId = alertSnap[i].ModelId; m.AdviseOperation = OperateStyle.Reset; m.AdviceType = CalculationOriginType.Alarm; m.LastUpdateTime = DateTime.Now; m.Status = 1; resetList.Add(m); } } else { AdviceModel m = new AdviceModel(); m.WindturbineId = alertSnap[i].WindturbineId; m.StationId = alertSnap[i].StationId; m.ModelId = alertSnap[i].ModelId; m.AdviseOperation = OperateStyle.Reset; m.AdviceType = CalculationOriginType.Alarm; m.LastUpdateTime = DateTime.Now; m.Status = 1; resetList.Add(m); } } } #endregion if (inputSpeedDic == null || inputSpeedDic.Count <= 0) GetWindturbineInputWindSpeed(); D("=============================="); D("======启停推荐(10.15)======"); D("=============================="); //WXW #region 计算需要启停的风机2.0 List resetWindturbine = resetList.Select(s => s.WindturbineId).ToList(); #region 风机启动推荐算法 /* * 推荐启动逻辑: * 当风机没有被复位, * 且风机正在待机, * 且没有被挂牌操作, * 现场没有人员在风机上(就地维护), * 风资源良好(当前风速达到启动风速,并且5分钟的平均风速良好), * 且风机不是大风天,则推荐风机启动) */ var startSuggest = AdviceCache.Instance.dicWindturbineInfo.Where(w => !resetWindturbine.Contains(w.Key)&& // 非复位 w.Value.StatusCode.TagData.doubleValue.HasValue && w.Value.StatusCode.TagData.doubleValue.Value== (int)WStatus.Standby && // 待机中 w.Value.LockCode.TagData.doubleValue.HasValue && w.Value.LockCode.TagData.doubleValue.Value == (int)HungType.UnLock && //未挂牌 inputSpeedDic.ContainsKey(w.Key)&& w.Value.WindSpeedCode.TagData.doubleValue.HasValue && w.Value.WindSpeedCode.TagData.doubleValue.Value > inputSpeedDic[w.Key] &&// 当前风速好 w.Value.WindSpeedCode.TagData.doubleValue.Value < thereIsSuperWind && // 不是超级大风天 w.Value.WindSpeedCodeFiveMin.TagData.doubleValue.HasValue && w.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value > inputSpeedDic[w.Key]//5分钟的风速好 ); foreach (var kv in startSuggest) { AdviceModel m = new AdviceModel(); m.WindturbineId = kv.Value.WindturbineId; m.StationId = kv.Value.Windturbine.WindPowerStationId; m.ModelId = kv.Value.Windturbine.ModelId; m.AdviseOperation = OperateStyle.Start; m.AdviceType = CalculationOriginType.RealTimeStatus; m.LastUpdateTime = DateTime.Now; m.AdviceExecuteTime = DateTime.Now; m.Status = 1; startList.Add(m); D("Start=====>"+m.WindturbineId+"\t"+kv.Value.WindSpeedCode.TagData.doubleValue.Value.ToString("f2")+"\t\t\t\t\t----------->启动"); } #endregion #region 风机停机推荐算法 // 此处没有添加针对台风模式和冰冻模式的算法 /* * 台风模式:一般当风大于约25m/s(各机型不一样)的切出风速,风机就会停机,桨叶收起,然后对风偏航,这在海上比较重要 * * 冰冻模式:当风速和功率比值不对,并且气温在±5℃,湿度在某值时,桨叶可能有结冰现象,此时也应该推荐停机 * * 以下实现的算法: * 在风机没有被复位,而且正在运行,也没有挂牌时,风速渐小(5分钟的平均风速小于切入风速),当前风速小于切入风,风机产生的功率某值(0),表示风机发电条件已经很不满足,则推荐风机停机 */ var stopSuggest = AdviceCache.Instance.dicWindturbineInfo.Where(t => !resetWindturbine.Contains(t.Key) && // 非复位 // 正在运行 t.Value.StatusCode.TagData.doubleValue.HasValue && windturbineRunStatueArray.Contains(HelpperMethod.GetWindturbineStatus(t.Value.StatusCode.TagData.doubleValue.Value)) && t.Value.LockCode.TagData.doubleValue.HasValue && t.Value.LockCode.TagData.doubleValue.Value == (int)HungType.UnLock && //未挂牌 t.Value.WindSpeedCode.TagData.doubleValue.HasValue && t.Value.WindSpeedCode.TagData.doubleValue.Value < thereIsAlmostNoWind && // 当前风不好了 t.Value.WindSpeedCodeFiveMin.TagData.doubleValue.HasValue && t.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value < thereIsAlmostNoWind &&//5分钟的风速也不好 t.Value.WindturbinePower.TagData.doubleValue.HasValue && t.Value.WindturbinePower.TagData.doubleValue.Value< thereIsAlmostNoPower //功率小于某个值 ); foreach (var kv in stopSuggest) { AdviceModel m = new AdviceModel(); m.WindturbineId = kv.Value.WindturbineId; m.StationId = kv.Value.Windturbine.WindPowerStationId; m.ModelId = kv.Value.Windturbine.ModelId; m.AdviseOperation = OperateStyle.Start; m.AdviceType = CalculationOriginType.RealTimeStatus; m.LastUpdateTime = DateTime.Now; m.AdviceExecuteTime = DateTime.Now; m.Status = 1; stopList.Add(m); D("Stop =====>" + m.WindturbineId + "\t" + kv.Value.WindSpeedCode.TagData.doubleValue.Value.ToString("f2") + "\t=====================>停机[" + kv.Value.WindturbinePower.TagData.doubleValue.Value.ToString("f2")+"kW.h]"); } #endregion #endregion #region 2019/10/15前的推荐算法(弃用) 计算需要启停的风机 //IList resetWindturbineIdList = resetList.Select(s => s.WindturbineId).ToList(); ////排除需要复位的风机 //IList calcWindturbineKeyList = AdviceCache.Instance.dicWindturbineInfo.Keys.ToList(); //for (int i = 0; i < calcWindturbineKeyList.Count; i++) //{ // WindturbineInfo info = AdviceCache.Instance.dicWindturbineInfo[calcWindturbineKeyList[i]]; // // 排除需要复位的风机 // if (!resetWindturbineIdList.Contains(calcWindturbineKeyList[i])) // { // WStatus? st = null; // HungType? hungType = null; // double? windSpeed = null; // if (info.StatusCode.TagData.doubleValue.HasValue) // st = HelpperMethod.GetWindturbineStatus(info.StatusCode.TagData.doubleValue.Value); // if (info.LockCode.TagData.doubleValue.HasValue) // hungType = HelpperMethod.GetHungType(info.LockCode.TagData.doubleValue.Value); // if (info.WindSpeedCode.TagData.doubleValue.HasValue) // windSpeed = info.WindSpeedCode.TagData.doubleValue.Value; // if (!inputSpeedDic.ContainsKey(info.WindturbineId)) // continue; // //获取切入风 // double putSpeed = inputSpeedDic[info.WindturbineId]; // WStatus[] allowStopStatusArr = { WStatus.Online, WStatus.OnPower, WStatus.Start }; // //如果风机状态不为空,风速不为空,且未挂牌 // if (st.HasValue && hungType.HasValue && windSpeed.HasValue && hungType.Value == HungType.UnLock) // { // //如果风机当前状态为待机 // if (st == WStatus.Standby) // { // //如果当前风速大于风机的切入风速,则推荐启动,否则不做任何操作 // if (windSpeed.HasValue && windSpeed >= 3.5 ) // { // AdviceModel m = new AdviceModel(); // m.WindturbineId = info.WindturbineId; // m.StationId = info.Windturbine.WindPowerStationId; // m.ModelId = info.Windturbine.ModelId; // m.AdviseOperation = OperateStyle.Start; // m.AdviceType = CalculationOriginType.RealTimeStatus; // m.LastUpdateTime = DateTime.Now; // m.AdviceExecuteTime = DateTime.Now; // m.Status = 1; // stopList.Add(m); // } // } // //如果当前风机状态是并网状态,启动状态,上电状态, // else if (WStatus.Online==st.Value) // { // //如果当前风小于切入风 // if (windSpeed < 3.0) // { // AdviceModel m = new AdviceModel(); // m.WindturbineId = info.WindturbineId; // m.StationId = info.Windturbine.WindPowerStationId; // m.ModelId = info.Windturbine.ModelId; // m.AdviseOperation = OperateStyle.Stop; // m.AdviceType = CalculationOriginType.RealTimeStatus; // m.LastUpdateTime = DateTime.Now; // m.AdviceExecuteTime = DateTime.Now; // m.Status = 1; // startList.Add(m); // } // } // } // } //} #endregion //Console.WriteLine("风机实时推荐计算完毕"); IList finalResultList = resetList.Union(stopList).Union(startList).ToList(); //将最终结果添加到结果缓存中 AdviceCache.Instance.AdviceListAdd(finalResultList); } /// /// 全场无风,推荐待机状态的风机打维护(减少耗电) 或者 全场有风,风的条件比较好,将维护状态下的风机推荐为取消维护 /// public void TryMaintainWindturbine() { try { IList maintainList = new List(); Dictionary windDictionary = AdviceCache.Instance.dicWindturbineInfo; // 利用场站分组 var stationGroup = windDictionary.GroupBy(x => x.Value.Windturbine.WindPowerStationId); D("=============================="); D("======维护推荐(10.15)======"); D("=============================="); // 针对各个场站计算出一个平均风速.针对每个期计算出平均风速 foreach (var item in stationGroup) //(Grouping> item in stationGroup) { string stationName = item.Key; // 全场站的5分钟平均风速 var stationAverage = item.Where(w=>w.Value.StatusCode.TagData.doubleValue.Value!= (int)WStatus.Offline).Select(s => s.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value).Average();//(k => k.Select(m => m.WindSpeedCode.TagData.doubleValue.Value).ToList().Average());//item.Select(s => s.Values)//.Select(w => w.WindSpeedCode.TagData.longValue).Average()); var maxV = item.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(s => s.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value).Max(); var minV = item.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(s => s.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value).Min(); //D("[+]场站:" + stationName.PadRight(24) + "\t" + "最高值:" + maxV.ToString("0.000").PadRight(20) + "\t" + "最低值:" + minV.ToString("0.000").PadRight(20) + "\t" + "平均值:" + stationAverage.ToString("0.000")); // 按照项目5分钟平均风速 分组 var projectGroup = item.GroupBy(p => p.Value.Windturbine.ProjectId); foreach (var project in projectGroup) { string projectName = project.Key; var projectAverage = project.Select(a => a.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value).Average(); var pMax = project.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(a => a.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value).Max(); var pMin = project.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(a => a.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value).Min(); //D("[+]项目 :" + projectName.PadRight(16) + "最高值:" + pMax.ToString("0.000").PadRight(20) + "\t" + "最低值:" + pMin.ToString("0.000").PadRight(20) + "\t" + "平均值:" + projectAverage.ToString("0.000")); // 当前项目的平均风速 var projectCurrentAverage = project.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(a => a.Value.WindSpeedCode.TagData.doubleValue.Value).Average(); var currentMax = project.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(a => a.Value.WindSpeedCode.TagData.doubleValue.Value).Max(); var currentMin = project.Where(w => w.Value.StatusCode.TagData.doubleValue.Value != (int)WStatus.Offline).Select(a => a.Value.WindSpeedCode.TagData.doubleValue.Value).Min(); //D("[+]项目当前:" + projectName.PadRight(16) + "最高值:" + currentMax.ToString("0.000").PadRight(20) + "\t" + "最低值:" + currentMin.ToString("0.000").PadRight(20) + "\t" + "平均值:" + projectCurrentAverage.ToString("0.000")); if (thereIsNoWind > projectCurrentAverage && thereIsNoWind > stationAverage)// && thereIsNoWind > currentMax) { // 项目中 如果最大的风速还是比我们预定的风速还小,证明整个项目区域的风速就比较小 满足全场无风了 #region 推荐维护 /* * 风机维护推荐算法: * * 风机没有被挂牌 * 风机在待机状态 * 5分钟平均风速小于2.7m/s * 风机本身风速小于2.7m/s * 机舱温度大于0℃ * **/ var turbineDictionary = project.Where(w => !w.Value.Windturbine.ModelId.Contains("UP105") && w.Value.LockCode.TagData.doubleValue.Value == (int)HungType.UnLock && HelpperMethod.GetWindturbineStatus(w.Value.StatusCode.TagData.doubleValue.Value) == WStatus.Standby && w.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value < thereIsNoWind && w.Value.WindSpeedCode.TagData.doubleValue.Value < thereIsNoWind && w.Value.BoxTemperature.TagData.doubleValue > maintainLowTemperature //冬天的时候就不推荐全场无风了,需要保持偏航和内部设备运转 ); foreach (var kv in turbineDictionary) { D("[+]:风机:" + kv.Value.WindturbineId + "\t风速" + kv.Value.WindSpeedCode.TagData.doubleValue.Value.ToString("0.0000") + "\t----->推荐打维护"); AdviceModel m = new AdviceModel(); m.WindturbineId = kv.Value.WindturbineId; m.StationId = kv.Value.Windturbine.WindPowerStationId; m.ModelId = kv.Value.Windturbine.ModelId; m.AdviseOperation = OperateStyle.Maintain;// 建议维护 m.AdviceType = CalculationOriginType.RealTimeStatus; // 实时状态 m.LastUpdateTime = DateTime.Now; m.AdviceExecuteTime = DateTime.Now; m.Status = 1; maintainList.Add(m); } #endregion } else if (projectCurrentAverage > theWindIsComing && stationAverage > theWindIsComing) { // 当前项目和场站的平均风速都达到了很好的有风条件,则满足全场有风 #region 推荐取消维护 /* * 取消维护推荐算法: * * 风机没有挂牌 * 风机正在维护状态 * 风机的5分钟平均风速良好 * * 或者 * * 风机没有挂牌 * 风机正在 维护状态 * 风机的机舱温度太低(-10℃) */ var turbineDictionary = project.Where(w => ( !w.Value.Windturbine.ModelId.Contains("UP105") && w.Value.LockCode.TagData.doubleValue.Value == (int)HungType.UnLock && HelpperMethod.GetWindturbineStatus(w.Value.StatusCode.TagData.doubleValue.Value) == WStatus.Maintain && w.Value.WindSpeedCodeFiveMin.TagData.doubleValue.Value > theWindIsComing && w.Value.WindSpeedCode.TagData.doubleValue.Value > theWindIsComing ) || (// 维护时机舱温度过低,推荐取消维护 !w.Value.Windturbine.ModelId.Contains("UP105") && w.Value.LockCode.TagData.doubleValue.Value == (int)HungType.UnLock && HelpperMethod.GetWindturbineStatus(w.Value.StatusCode.TagData.doubleValue.Value) == WStatus.Maintain && w.Value.BoxTemperature.TagData.doubleValue < unMaintainLowTemperature ) ); foreach (var kv in turbineDictionary) { D("[+]:风机:" + kv.Value.WindturbineId + "\t风速" + kv.Value.WindSpeedCode.TagData.doubleValue.Value.ToString("0.0000") + "\t----->推荐取消维护["+kv.Value.BoxTemperature.TagData.doubleValue.Value.ToString("f2")+"℃]"); AdviceModel m = new AdviceModel(); m.WindturbineId = kv.Value.WindturbineId; m.StationId = kv.Value.Windturbine.WindPowerStationId; m.ModelId = kv.Value.Windturbine.ModelId; m.AdviseOperation = OperateStyle.UnMaintain;//建议取消维护 m.AdviceType = CalculationOriginType.RealTimeStatus; // 实时状态 m.LastUpdateTime = DateTime.Now; m.AdviceExecuteTime = DateTime.Now; m.Status = 1; maintainList.Add(m); } #endregion } } } D("==============================>"); //将最终结果添加到结果缓存中 AdviceCache.Instance.AddMaintainAdvice(maintainList); } catch (Exception e) { D(e.ToString()); } } bool allowDebug = ConfigurationManager.AppSettings["AllowDebug"].ToUpper() == "Y"; bool allowPrint = ConfigurationManager.AppSettings["AllowPrint"].ToUpper() == "Y"; private void D(string debugText) { try { if (allowDebug) { System.Diagnostics.Debug.WriteLine(debugText); } if (allowPrint) { Console.WriteLine(debugText); } } catch (Exception ex) { //logger.Info(ex.Message); System.Diagnostics.Debug.WriteLine(ex.ToString()); } } public void GetWindturbineInputWindSpeed() { if (inputSpeedDic == null) inputSpeedDic = new Dictionary(); using (GDNXFDDbContext ctx = new GDNXFDDbContext()) { string sql = @"select id, windturbineid, recorddate, inputsmall from inputoroutputspeedtotal t where t.recorddate = (select max(recorddate) from inputoroutputspeedtotal)"; IList speedTotalList = ctx.InputOrOutputSpeedTotal.SqlQuery(sql, new object[] { }).ToList(); for (int i = 0; i < speedTotalList.Count; i++) { if (!inputSpeedDic.ContainsKey(speedTotalList[i].WindturbineId)) inputSpeedDic.Add(speedTotalList[i].WindturbineId, speedTotalList[i].InputSmall); } } } } } /* private enum FGLTrend { Up, Down, NoChange } private FGLTrend GetFGLYC(string stationID, out double guessMax) { try { string[] unifmCodes = ConfigurationManager.AppSettings["StationFGLYC"].Split(',');// 配置中的Code使用','分隔 Dictionary shotestGuess = WisdomClient.RestfulClient.findLatestByThingCodes("station", stationID, unifmCodes); //if (stationID == "SBQ_FDC") //{ // guessMax = shotestGuess.Select(s => s.Value.doubleValue.Value).Max(); // string[] unifmCodesSBQB = ConfigurationManager.AppSettings["StationFGLYCSBQ"].Split(',');// 配置中的Code使用','分隔 // Dictionary shotestGuessSBQB = WisdomClient.RestfulClient.findLatestByThingCodes("station", stationID, unifmCodesSBQB); // double guessMaxTmp = shotestGuessSBQB.Select(s => s.Value.doubleValue.Value).Max(); // guessMax = guessMax > guessMaxTmp ? guessMaxTmp : guessMaxTmp;//确定峰值的最大 // FGLTrend SQBTrendA = shotestGuess["FCFGCDQ0001"].doubleValue.Value < shotestGuess["FCFGCDQ0016"].doubleValue.Value ? FGLTrend.Up : FGLTrend.Down; // FGLTrend SQBTrendB = shotestGuessSBQB["FCFGCDQ0001"].doubleValue.Value < shotestGuessSBQB["FCFGCDQ0016"].doubleValue.Value ? FGLTrend.Up : FGLTrend.Down; // // 同升则升 不升则视为降(风速均匀也视为降) // return (SQBTrendA == SQBTrendB && SQBTrendB == FGLTrend.Up) ? FGLTrend.Up : FGLTrend.Down; //} //else //{ // FCFGCDQ0001 // FCFGCDQ0016 // 取最近的值和最未来的预测值比较,如果预测风势降低,则返回Down,如果升高则返回UP // 还要返回最后的预测风速 // guessMax = shotestGuess.Select(s => s.Value.doubleValue.Value).Max(); // 预测风速中的峰值 return shotestGuess["FCFGCDQ0001"].doubleValue.Value < shotestGuess["FCFGCDQ0016"].doubleValue.Value ? FGLTrend.Up : FGLTrend.Down; //} } catch (Exception e) { //System.Diagnostics.Debug.WriteLine(e.ToString()); guessMax = 100;// 返回一个虚拟的大值 return FGLTrend.Up; } } */