private void save(string fullpath) { var model = this._model; //提示是否保存光谱库,用于建模 this._model.FullPath = fullpath; var finfo = new FileInfo(fullpath); this._model.Name = finfo.Name.Replace(finfo.Extension, ""); if (MessageBox.Show("是否将建模所用的光谱库保存到模型中? 备注:保存在模型中方可对模型进行修改。", "信息提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No) { model = Serialize.DeepClone <PLSModel>(this._model); model.LibBase = null; var lst = model.SubModels.Where(d => d.Trained == true).ToArray(); model.SubModels.Clear(); foreach (var m in lst) { model.SubModels.Add(m); } } model.CreateTime = DateTime.Now; model.Edited = false; model.Trained = true; if (model.Save()) { MessageBox.Show("捆绑模型保存成功!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); this._model.Edited = false; } else { MessageBox.Show("捆绑模型保存失败!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } }
public void Train(SpecBase lib, bool needFilter = true) { //过滤掉性质有NaN的数据 lib.FilterNaN(); int[] idxs = lib.Specs.Select((d, idx) => new { s = d, idx = idx }).Where(d => d.s.Usage != UsageTypeEnum.Ignore).Select(d => d.idx).ToArray(); this._lib = Serialize.DeepClone <SpecBase>(lib.SubLib(idxs)); if (needFilter && this._filters != null) { this._lib.SetX(Preprocesser.Process(this._filters, this._lib), true); } //PCA分解 var handler = Tools.ModelHandler; if (this._maxRank < 1) { this._maxRank = 10; } this._maxRank = Math.Min(this._maxRank, this._lib.X.Dimensions[1]); var r = handler.IdentifyTrain(3, this._lib.X, this._maxRank); this._p = (MWNumericArray)r[0]; this._w = (MWNumericArray)r[1]; this._t = (MWNumericArray)r[2]; this._trained = true; }
private void btnModelExtent_Click(object sender, EventArgs e) { if (this._lib == null || this._baseModel == null) { return; } bool needcv = false; if (MessageBox.Show("是否进行交互验证和外部验证?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { needcv = true; } this._model = Serialize.DeepClone <IdentifyModel>(this._baseModel); this._model.Name = this._lib.Name; this.btnModelExtent.Text = "正在计算"; this.btnRebuild.Enabled = false; this.btnModelExtent.Enabled = false; this.btnLoadModel.Enabled = false; this.btnLoadSpec.Enabled = false; this.toolStripProgressBar1.Visible = true; int num = int.Parse(this.textBox1.Text); int numofId = int.Parse(this.txbnumofId.Text); Action a = () => { this._model.Train(this._lib); var lib = this._model.SpecLib.Clone(); lib.Merger(this._baseModel.SpecLib); if (needcv) { this._cvLst = this._model.CrossValidation(lib, false); this._vLst = this._model.Validation(lib, false); } else { this._vLst = null; this._cvLst = null; } this._model.Train(lib, false); //显示 this.showdata(num, numofId); if (this.InvokeRequired) { ThreadStart s = () => { MessageBox.Show("建模完成"); }; this.Invoke(s); } else { MessageBox.Show("建模完成"); } }; a.BeginInvoke(null, null); }
public void LoadData(SpecBase filterlib, SpecBase baselib) { this._olib = Serialize.DeepClone <SpecBase>(filterlib); this._nlib = Serialize.DeepClone <SpecBase>(baselib); // this.renderGrid(UsageTypeEnum.Node); if (cbxSamSelector.SelectedIndex == 0) { this.renderGrid(UsageTypeEnum.Node); } this.combRender(); }
public BindResult PredictForAPI(Spectrum spec, bool needFilter = true, int numOfId = 5, int topK = 1) { if (this.IdModels.Count > 0) { IdentifyResult iresult = null; foreach (var i in this.IdModels) { iresult = CombineIdResult(iresult, i.Predict(spec, needFilter, numOfId, topK)); } if (iresult != null && iresult.Items.Where(d => d.Result).Count() > 0) { iresult = IdentifyModel.GetPredictValue(iresult, iresult.Items.Length, numOfId); return(new BindResult() { MethodType = PredictMethod.Identify, Result = iresult }); } } if (this.FitModels.Count > 0) { var fitmodel = Serialize.DeepClone <FittingModel>(this.FitModels.First()); for (int i = 1; i < this.FitModels.Count; i++) { fitmodel.SpecLib.Merger(this.FitModels[i].SpecLib); } var flst = new List <FittingResult>();//这里需要修改,将List<FittingResult>改为FittingResult flst.Add(fitmodel.Predict(spec, needFilter, numOfId, topK)); if (flst.Where(d => d.Result).Count() > 0) { return new BindResult() { MethodType = PredictMethod.Fitting, Result = flst.Where(d => d.Result).OrderByDescending(d => d.TQ).FirstOrDefault() } } ; } if (this.PLS != null) { var plsr = this.PLS.Predict(spec, needFilter, numOfId); return(new BindResult() { MethodType = PredictMethod.PLSBind, Result = plsr }); } return(new BindResult() { MethodType = PredictMethod.None }); }
public void Train(SpecBase lib, bool needFilter = true) { //过滤掉性质有NaN的数据 lib.FilterNaN(); int[] idxs = lib.Specs.Select((d, idx) => new { s = d, idx = idx }).Where(d => d.s.Usage != UsageTypeEnum.Ignore).Select(d => d.idx).ToArray(); this._lib = Serialize.DeepClone <SpecBase>(lib.SubLib(idxs)); if (needFilter && this._filters != null) { this._lib.SetX(Preprocesser.Process(this._filters, this._lib), true); } this._trained = true; }
private void btnSave_Click(object sender, EventArgs e) { try { this._model.MDMin = double.Parse(this.txbMash.Text); this._model.SRMin = double.Parse(this.txbSR.Text); this._model.Nonnegative = this.txbNotneg.Checked; } catch { MessageBox.Show("您输入的数字有误"); return; } SaveFileDialog mySaveFileDialog = new SaveFileDialog(); if (this._model.AnnType == PLSAnnEnum.None) { mySaveFileDialog.Filter = string.Format("{1} (*.{0})|*.{0}", FileExtensionEnum.PLS1, FileExtensionEnum.PLS1.GetDescription()); } else { mySaveFileDialog.Filter = string.Format("{1} (*.{0})|*.{0}", FileExtensionEnum.PLSANN, FileExtensionEnum.PLSANN.GetDescription()); } mySaveFileDialog.InitialDirectory = Busi.Common.Configuration.FolderMModelLib; mySaveFileDialog.FileName = string.Format("{0}-{1}", this._model.LibBase.Name, this._model.Comp.Name); if (mySaveFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK) { return; } try { this._model.FullPath = mySaveFileDialog.FileName; var model = Serialize.DeepClone <PLSSubModel>(this._model); model.LibBase = null; model.ParentModel = null; model.Trained = true; model.Save(); this.DialogResult = System.Windows.Forms.DialogResult.OK; this.Close(); } catch (Exception ex) { log.Error(ex); MessageBox.Show("保存失败!"); } }
void dataGridView2_CellEndEdit(object sender, DataGridViewCellEventArgs e) { if (e.ColumnIndex != 0) { return; } for (int i = 0; i < this.dataGridView2.Rows.Count; i++) { if (i != e.RowIndex) { this.dataGridView2.Rows[i].Cells[0].Value = false; } } var cname = this.dataGridView2.Rows[e.RowIndex].Tag.ToString(); this._model.Comp = null; if (this._model.Identify != null) { var c = this._model.Identify.Where(d => d.SpecLib.Components.Contains(cname)).Select(d => d.SpecLib.Components[cname]).FirstOrDefault(); if (c != null) { this._model.Comp = Serialize.DeepClone <Component>(c); } } if (this._model.Comp == null && this._model.Fittings != null) { var c = this._model.Fittings.Where(d => d.SpecLib.Components.Contains(cname)).Select(d => d.SpecLib.Components[cname]).FirstOrDefault(); if (c != null) { this._model.Comp = Serialize.DeepClone <Component>(c); } } if (this._model.Comp == null && this._model.PLS1 != null) { if (this._model.PLS1.Comp.Name == cname) { this._model.Comp = Serialize.DeepClone <Component>(this._model.PLS1.Comp); } } if (this._model.Comp == null && this._model.PLSANN != null) { if (this._model.PLSANN.Comp.Name == cname) { this._model.Comp = Serialize.DeepClone <Component>(this._model.PLSANN.Comp); } } }
private void btnSave_Click(object sender, EventArgs e) { var model = this._model; if (model == null || model.LibBase == null || model.LibBase.Count == 0) { return; } if (String.IsNullOrWhiteSpace(this._model.FullPath)) { SaveFileDialog mySaveFileDialog = new SaveFileDialog(); mySaveFileDialog.Filter = string.Format("{1} (*.{0})|*.{0}", FileExtensionEnum.FitLib, FileExtensionEnum.FitLib.GetDescription()); mySaveFileDialog.InitialDirectory = Busi.Common.Configuration.FolderMFit; mySaveFileDialog.FileName = this._model.LibBase.Name; if (mySaveFileDialog.ShowDialog() != DialogResult.OK) { return; } this._model.FullPath = mySaveFileDialog.FileName; var finfo = new FileInfo(mySaveFileDialog.FileName); this._model.Name = finfo.Name.Replace(finfo.Extension, ""); } if (MessageBox.Show("是否将建模所用的光谱库保存到模型中? 备注:保存在模型中方可对模型进行修改。", "信息提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No) { model = Serialize.DeepClone <FittingModel>(this._model); model.LibBase = null; } model.Train(this._model.LibBase); model.CreateTime = DateTime.Now; model.Edited = false; if (model.Save()) { MessageBox.Show("拟合库保存成功!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); this._model.Edited = false; } else { MessageBox.Show("拟合库保存失败!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } this.setTitle(); }
/// <summary> /// 添加新的预处理方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void treeMethod_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { var node = e.Node as MyTreenode; if (node == null) { return; } if (node.Preocesser.Filter.FType == FilterType.VarFilter)//如果是区间设置,需要先将之前的全部处理一次 { Action a = () => { this.compute(); var p = Serialize.DeepClone <Preprocesser>(node.Preocesser); p.SpecsInput = this._lastRowSpec; var dlg = new VarRegionSet(); dlg.Width = (int)(this.TopLevelControl.Width * 0.85); dlg.Height = (int)(this.TopLevelControl.Height * 0.9); NIR.Component c = null; if (this.GetComponent != null) { c = this.GetComponent(); } if (c == null) { c = p.SpecsInput.Components.FirstOrDefault(); } if (dlg.ShowDialog(p, c) == DialogResult.OK) { this.addRow(p); } }; this.BeginInvoke(a); } else { this.addRow(Serialize.DeepClone <Preprocesser>(node.Preocesser)); } }
private void btnRebuild_Click(object sender, EventArgs e) { if (this._lib == null || this._baseModel == null) { return; } bool needcv = false; if (MessageBox.Show("是否进行交互验证和外部验证?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { needcv = true; } this._model = Serialize.DeepClone <PLSSubModel>(this._baseModel); this.btnRebuild.Text = "正在计算"; this.btnRebuild.Enabled = false; this.btnLoadModel.Enabled = false; this.btnLoadSpec.Enabled = false; this.toolStripProgressBar1.Visible = true; Action a = () => { if (needcv) { this._cvLst = this._model.CrossValidation(this._lib); this._vLst = this._model.Validation(this._lib); } else { this._cvLst = null; this._vLst = null; } this._model.Train(this._lib); //显示 this.showdata(); }; a.BeginInvoke(null, null); }
private void train() { try { for (int i = 0; i < this._Nodes.Count; i++) { var pls = this._Nodes[i].PLS.Model; var needtrain = (bool)this.dataGridView1.Rows[i].Cells[3].Value; var needOuter = (bool)this.dataGridView1.Rows[i].Cells[4].Value; if (pls.Comp == this._model.Comp) { continue; } if (needtrain) { // Pharse 1 设置方法和参数 // 预处理 pls.Filters = new List <IFilter>(); foreach (var f in _model.Filters) { pls.Filters.Add(Serialize.DeepClone <IFilter>(f)); } pls.MaxFactor = this._model.MaxFactor; pls.Factor = this._model.Factor; pls.ANNAgrus = this._model.ANNAgrus; pls.ANNModel = this._model.ANNModel; pls.AnnType = this._model.AnnType; pls.FANNModels = this._model.FANNModels; pls.Method = this._model.Method; pls.SRMin = this._model.SRMin; pls.Nonnegative = this._model.Nonnegative; if (needOuter) { pls.OutlierNames = Serialize.DeepClone <List <string> >(this._model.OutlierNames); } // Pharse 2 交互验证 this.c(i, "正在交互验证"); var dt = DateTime.Now; this._Nodes[i].PLS.CVResult = pls.CrossValidation(pls.LibBase); // Pharse 3 外部验证 this.c(i, "正在外部验证"); //pls.Train(pls.LibBase); //var lst = pls.LibBase.Where(d => d.Usage == UsageTypeEnum.Validate); var span1 = (DateTime.Now - dt).TotalMilliseconds; //再外部验证 dt = DateTime.Now; this._Nodes[i].PLS.VResult = pls.Validation(pls.LibBase); var span2 = (DateTime.Now - dt).TotalMilliseconds; log.DebugFormat("{0}个校正集,交互验证花费{1}ms,{2}个验证集,外部验证花费{3}ms", pls.LibBase.Specs.Where(d => d.Usage == UsageTypeEnum.Calibrate).Count(), span1, pls.LibBase.Specs.Where(d => d.Usage == UsageTypeEnum.Validate).Count(), span2); pls.MDMin = pls.Mdt[pls.MaxFactor - 1]; pls.NNDMin = pls.NNdt[pls.MaxFactor - 1]; // Pharse 4 this.c(i, "完成"); this._Nodes[i].PLS.ActiveStep = 4; var parent = this._Nodes[i].TreeView; if (parent.InvokeRequired) { ThreadStart s = () => { this._Nodes[i].ShowText(); }; parent.Invoke(s); } else { this._Nodes[i].ShowText(); } //使用完后立即回收lib if (pls.Lib != null) { pls.Lib.Dispose(); } } } } catch (OutOfMemoryException ex) { log.Error(ex); MessageBox.Show("对不起,性质数量太多,内存溢出了,请关闭本窗口,保存已建好性质的子模型后,重启本软件,谢谢!"); } finally { if (this.button1.InvokeRequired) { ThreadStart s = () => { this.button1.Enabled = true; }; this.button1.Invoke(s); } else { this.button1.Enabled = true; } if (this.button2.InvokeRequired) { ThreadStart s = () => { this.button2.Enabled = true; }; this.button2.Invoke(s); } else { this.button1.Enabled = true; } if (this.progressBar1.InvokeRequired) { ThreadStart s = () => { this.progressBar1.Visible = false; }; this.progressBar1.Invoke(s); } else { this.progressBar1.Visible = false; } this._busying = false; } }
public Component Clone() { return(Serialize.DeepClone <Component>(this)); }
public PLS1Result[] CrossValidation(SpecBase libb, bool needFilter = true, int numOfId = 5) { var lib = libb.Clone(); //过滤掉性质有NaN的数据 lib.FilterNaN(this._comp); foreach (var s in lib.Specs) { if (this._OutlierNames.Contains(s.Name)) { s.Usage = UsageTypeEnum.Ignore; } } //lib.Specs = lib.Specs.Where(d => !this._OutlierNames.Contains(d.Name)).ToList(); if (!this._trained) { this.Train(lib, needFilter); } var clib = lib.SubLib(UsageTypeEnum.Calibrate); if (clib.Count == 0) { return(null); } if (needFilter && this._filters != null) { clib.X = Preprocesser.Process(this._filters, clib.X); } var handler = Tools.ModelHandler; MWNumericArray Ylast, SR, MD, nd; if (this._annType != PLSAnnEnum.None) { var model = Serialize.DeepClone <PLSSubModel>(this); model.Train(lib, true); var pls = handler.PLS1Predictor(5, clib.X, model.Scores, model.Loads, model.Weights, model.Bias, model.Score_Length, model.CenterSpecData, model.CenterCompValue, (int)this._method); var toolHandler = Tools.ToolHandler; Ylast = (MWNumericArray)pls[0]; SR = (MWNumericArray)pls[1]; MD = (MWNumericArray)pls[2]; nd = (MWNumericArray)pls[3]; var mscores = (MWNumericArray)toolHandler.Centring(1, pls[4], model.ScoresMean)[0]; double[] annrsult; var annp = handler.annp(1, mscores, model.ANNModel.w1, model.ANNModel.b1, model.ANNModel.w2, model.ANNModel.b2, model.ANNAgrus.F1.GetDescription(), model.ANNAgrus.F2.GetDescription())[0]; annrsult = (double[])((MWNumericArray)annp).ToVector(MWArrayComponent.Real); for (int row = 0; row < annrsult.Length; row++) { Ylast[row + 1, this._factor] = annrsult[row] + model.CenterCompValue; } } else { var pls = handler.PLS1CrossValidation(4, clib.X, clib.GetY(this._comp, true), this._maxFactor, (int)this._method); Ylast = (MWNumericArray)pls[0]; SR = (MWNumericArray)pls[1]; MD = (MWNumericArray)pls[2]; nd = (MWNumericArray)pls[3]; } var items = new List <PLS1Result>(); for (int i = 0; i < clib.Count; i++) { var c = this._comp.Clone(); var s = clib[i]; if (s.Components != null && s.Components.Contains(c.Name)) { c.ActualValue = s.Components[c.Name].ActualValue; } var r = new PLS1Result { MDMin = this._MDMin, NDMin = this._NNDMin, SRMin = this._SRMin, Comp = c, Spec = s, YLast = (double[])Tools.SelectRow(Ylast, i + 1).ToVector(MWArrayComponent.Real), SR = (double[])Tools.SelectRow(SR, i + 1).ToVector(MWArrayComponent.Real), MahDist = (double[])Tools.SelectRow(MD, i + 1).ToVector(MWArrayComponent.Real), ND = (double[])Tools.SelectRow(nd, i + 1).ToVector(MWArrayComponent.Real), Factor = this.Factor }; if (!double.IsNaN(r.YLast[0])) { items.Add(r); } } lib.Dispose(); clib.Dispose(); GC.Collect(); return(items.ToArray()); }
public static IdentifyResult GetPredictValue(IdentifyResult input, int num, int numOfId) { if (input == null || input.Items == null) { throw new ArgumentNullException(""); } var r = Serialize.DeepClone <IdentifyResult>(input); //重新复制原始光谱和wind for (int i = 0; i < r.Items.Length; i++) { r.Items[i].SpecOriginal = input.Items[i].SpecOriginal; r.Items[i].Wind = input.Items[i].Wind; } numOfId = numOfId < 1 ? 5 : numOfId; var predicts = r.Items.Where(d => d.Result).OrderByDescending(d => d.Result).ThenByDescending(d => d.TQ).Select(d => d.Spec.Components).Take(num); // var count = predicts.Count(); if (r.Components == null) { r.Components = r.Items.First().Spec.Components.Clone(); } int k = 0; int[] couter = new int[r.Components.Count]; int numCounter = 0; foreach (var p in predicts) { if (k == 0) { foreach (var c in r.Components) { c.PredictedValue = 0; } k++; } for (int i = 0; i < r.Components.Count; i++) { if (!double.IsNaN(p[i].ActualValue)) { r.Components[i].PredictedValue += p[i].ActualValue; couter[i]++; } } numCounter++; if (numCounter >= numOfId) { break; } } for (int i = 0; i < r.Components.Count; i++) { r.Components[i].PredictedValue = r.Components[i].PredictedValue / couter[i]; r.Components[i].Error = r.Components[i].PredictedValue - r.Components[i].ActualValue; } r.Spec = input.Spec; r.Items = r.Items.OrderByDescending(d => d.Result).ThenByDescending(d => d.TQ).ToArray(); return(r); }
private void btnCompute_Click(object sender, EventArgs e) { if (spec1 == null || spec2 == null) { MessageBox.Show(string.Format("第{0}条光谱为空,请先选择。", spec1 == null ? 1 : 2), "信息提示"); return; } int mwin = 0; if (!int.TryParse(txbmwin.Text, out mwin)) { MessageBox.Show("移动窗口大小必须为整数", "信息提示"); return; } IList <IFilter> filters = new List <IFilter>(); if (this._model != null) { if (this._model is IdentifyModel) { filters = ((IdentifyModel)this._model).Filters; } else if (this._model is FittingModel) { filters = ((FittingModel)this._model).Filters; } } var s1 = spec1.Clone(); var s2 = spec2.Clone(); //对光谱预处理 if (filters != null) { var ya = new MWNumericArray(s1.Data.Lenght, 1, s1.Data.Y); var yb = new MWNumericArray(s2.Data.Lenght, 1, s2.Data.Y); bool splitadd = false; var y1 = (MWNumericArray)ya.Clone(); var y2 = (MWNumericArray)yb.Clone(); var x1 = Serialize.DeepClone <double[]>(s1.Data.X); var x2 = Serialize.DeepClone <double[]>(s2.Data.X); var y1lst = new List <MWNumericArray>(); var x1lst = new List <double[]>(); var y2lst = new List <MWNumericArray>(); var x2lst = new List <double[]>(); foreach (var tf in filters) { var f = RIPP.Lib.Serialize.DeepClone <RIPP.NIR.Data.Filter.IFilter>(tf); if (f is Spliter) { if (splitadd) { x1lst.Add(x1); y1lst.Add(y1); x2lst.Add(x2); y2lst.Add(y2); } splitadd = false; y1 = (MWNumericArray)ya.Clone(); y2 = (MWNumericArray)yb.Clone(); x1 = Serialize.DeepClone <double[]>(s1.Data.X); x2 = Serialize.DeepClone <double[]>(s2.Data.X); } else { splitadd = true; } y1 = f.Process(y1); y2 = f.Process(y2); if (f.FType == FilterType.VarFilter) { x1 = f.VarProcess(x1); x2 = f.VarProcess(x2); } } if (splitadd) { x1lst.Add(x1); y1lst.Add(y1); x2lst.Add(x2); y2lst.Add(y2); } //合并 if (x1lst.Count > 0) { s1.Data.X = x1lst[0]; s1.Data.Y = (double[])y1lst[0].ToVector(MWArrayComponent.Real); s2.Data.X = x2lst[0]; s2.Data.Y = (double[])y2lst[0].ToVector(MWArrayComponent.Real); for (int i = 1; i < x1lst.Count; i++) { s1.Data.X = RIPP.NIR.Data.Tools.InsertColumn(s1.Data.X, x1lst[i], s1.Data.X.Length + 1); s1.Data.Y = RIPP.NIR.Data.Tools.InsertColumn(s1.Data.Y, (double[])y1lst[i].ToVector(MWArrayComponent.Real), s1.Data.Y.Length + 1); s2.Data.X = RIPP.NIR.Data.Tools.InsertColumn(s2.Data.X, x2lst[i], s2.Data.X.Length + 1); s2.Data.Y = RIPP.NIR.Data.Tools.InsertColumn(s2.Data.Y, (double[])y2lst[i].ToVector(MWArrayComponent.Real), s2.Data.Y.Length + 1); } } else { s1.Data.X = x1; s1.Data.Y = (double[])y1.ToVector(MWArrayComponent.Real); s2.Data.X = x2; s2.Data.Y = (double[])y2.ToVector(MWArrayComponent.Real); } //s1.Data.Y = (double[])y1.ToVector(MWArrayComponent.Real); //s2.Data.Y = (double[])y2.ToVector(MWArrayComponent.Real); } if (this._model is FittingModel) { var f = ((FittingModel)this._model).IdRegion; s1.Data.X = f.VarProcess(s1.Data.X); s2.Data.X = f.VarProcess(s2.Data.X); s1.Data.Y = f.VarProcess(s1.Data.Y); s2.Data.Y = f.VarProcess(s2.Data.Y); } //绘制 var lst = new List <Spectrum>(); lst.Add(s1); lst.Add(s2); this.specGraph3.DrawSpec(lst); this.specGraph3.SetTitle("预处理后光谱"); double[] tSQ; double tTQ; RIPP.NIR.Data.Tools.MWCorr(s1.Data.Y, s2.Data.Y, mwin, out tTQ, out tSQ); var spec = RIPP.Lib.Serialize.DeepClone <Spectrum>(s1); spec.Data.Y = tSQ; spec.Name = "SQ"; spec.Color = Color.Blue; this.specGraph2.DrawSpec(new List <Spectrum>() { spec }); this.txbTQ.Text = tTQ.ToString("f3"); this.txbSQ.Text = tSQ.Min().ToString("f3"); }
public SpecBase Clone() { return(Serialize.DeepClone <SpecBase>(this)); }
public Spectrum Clone() { return(Serialize.DeepClone <Spectrum>(this)); }
private void btnLoadModel_Click(object sender, EventArgs e) { OpenFileDialog myOpenFileDialog = new OpenFileDialog(); myOpenFileDialog.Filter = string.Format("{0} (*.{1})|*.{1}", FileExtensionEnum.PLSBind.GetDescription(), FileExtensionEnum.PLSBind); myOpenFileDialog.InitialDirectory = Busi.Common.Configuration.FolderBlendMod; if (myOpenFileDialog.ShowDialog() == DialogResult.OK) { var m = BindModel.ReadModel <PLSModel>(myOpenFileDialog.FileName); if (m == null || lib == null) { return; } if (m.SubModels.Count != this.lib.Components.Count) { MessageBox.Show(string.Format("参与混兑计算的光谱数量为{0},加载的捆绑模型子模型数据为{1},不匹配。", this.lib.Components.Count, m.SubModels.Count)); return; } this.toolStrip2.Enabled = false; this.btnLoadModel.Text = "正在计算"; this.progressBar1.Visible = true; Action a = () => { this.model = Serialize.DeepClone <PLSModel>(m); this.model.MixSpecs = new List <Spectrum>(); if (s1 != null) { this.model.MixSpecs.Add(s1); } if (s2 != null) { this.model.MixSpecs.Add(s2); } if (s3 != null) { this.model.MixSpecs.Add(s3); } int i = 0; foreach (var sm in this.model.SubModels) { sm.Comp = this.lib.Components[i]; sm.Train(this.lib); var cvlst = sm.CrossValidation(this.lib); if (this.specGridView1.InvokeRequired) { ThreadStart s = () => { this.add(cvlst, i); }; this.specGridView1.Invoke(s); } else { this.add(cvlst, i); } i++; } if (this.toolStrip2.InvokeRequired) { ThreadStart s = () => { this.progressBar1.Visible = false; this.btnLoadModel.Text = "应用模型"; this.toolStrip2.Enabled = true; }; this.toolStrip2.Invoke(s); } else { this.progressBar1.Visible = false; this.btnLoadModel.Text = "应用模型"; this.toolStrip2.Enabled = true; } }; a.BeginInvoke(null, null); } }
public void Train(Matrix x, Vector y) { //检查输入 if (x == null || y == null) { throw new ArgumentNullException(""); } if (x.ColumnCount != y.Count) { throw new ArgumentException("x,y长度不一致"); } if (this._MaxFactor <= 0) { throw new ArgumentOutOfRangeException(string.Format("Factor未设置或者为负,Factor={0}", this._MaxFactor)); } if (this._MaxFactor > x.RowCount) { throw new ArgumentOutOfRangeException(string.Format("主成分数不能大于样品数,Factor={0},Num ={1}", this._MaxFactor, x.RowCount)); } if (this._MaxFactor > x.ColumnCount) { throw new ArgumentOutOfRangeException(string.Format("主成分数不能大于波长点数,Factor={0},Num ={1}", this._MaxFactor, x.ColumnCount)); } this._x = Serialize.DeepClone <Matrix>(x); this._y = Serialize.DeepClone <Vector>(y); int sampleCount = this._x.ColumnCount; int pointCount = this._x.RowCount; this._centerSpecData = new DenseVector(pointCount); for (int i = 0; i < pointCount; i++) { var r = this._x.Row(i); this._centerSpecData[i] = r.Mean(); this._x.SetRow(i, r.Subtract(this._centerSpecData[i])); } this._centerCompValue = y.Mean(); y = (Vector)y.Subtract(this._centerCompValue); this._x = (Matrix)this._x.Transpose(); this._Weights = new DenseMatrix(pointCount, this._MaxFactor); this._Loads = new DenseMatrix(pointCount, this._MaxFactor); this._Scores = new DenseMatrix(sampleCount, this._MaxFactor); this._Bias = new DenseVector(this._MaxFactor); this._Score_Length = new DenseVector(this._MaxFactor); for (int f = 0; f < this._MaxFactor; f++) { var xt = this._x.Transpose(); var w = xt * this._y; var s = this._x * w; this._Score_Length[f] = Math.Sqrt(s.DotProduct(s)); w = w * this._Score_Length[f]; s = s / this._Score_Length[f]; var l = xt * s; this._Bias[f] = s.DotProduct(y); this._Weights.SetColumn(f, w); this._Scores.SetColumn(f, s); this._Loads.SetColumn(f, l); this._x = (Matrix)(this._x - s.OuterProduct(l)); this._y = (Vector)(y - s * this._Bias[f]); } this._isTrained = true; }
public List <PropertyTable> GetData(Specs s, BindModel predictor) { using (var db = new NIRCeneterEntities()) { var r = s.OilData; if (r != null) { return(r); } if (s == null || s.ResultObj == null) { return(null); } var pr = s.ResultObj; if (s.ResultObj.MethodType == PredictMethod.Integrate && predictor != null) { var papi = predictor.PredictForAPI(s.Spec, true); if (papi.MethodType == PredictMethod.Fitting || papi.MethodType == PredictMethod.Identify) { pr = papi; } } r = Serialize.DeepClone <List <PropertyTable> >(this._initP); OilInfoBEntity oil = null; switch (pr.MethodType) { case NIR.Models.PredictMethod.Identify: oil = getByName(s, pr, ref r); break; case NIR.Models.PredictMethod.Fitting: oil = getByRate(s, pr, ref r); break; case NIR.Models.PredictMethod.PLSBind: oil = getByProperties(s, pr, ref r); break; default: break; } GetNIRData(s, oil, ref r); if (oil != null) { r = r.OrderBy(d => (int)d.Table).ToList(); db.OilData.AddObject(new OilData() { SID = s.ID, Data = Serialize.ObjectToByte(r) }); db.SaveChanges(); } else { foreach (var t in r) { foreach (var dd in t.Datas) { if (dd.Value == 0) { dd.Value = double.NaN; } } } } return(r); } }
public bool APIGetData(BindModel predictor, ref Specs s) { log.Info("db before"); using (var db = new NIRCeneterEntities()) { var r = s.OilData; if (r != null) { return(true); } log.Info("db after"); if (s == null || s.ResultObj == null) { return(false); } var pr = s.ResultObj; if (s.ResultObj.MethodType == PredictMethod.Integrate && predictor != null) { var papi = predictor.PredictForAPI(s.Spec, true); if (papi.MethodType == PredictMethod.Fitting || papi.MethodType == PredictMethod.Identify) { pr = papi; } } r = Serialize.DeepClone <List <PropertyTable> >(this._initP); OilInfoBEntity oil = null; switch (pr.MethodType) { case NIR.Models.PredictMethod.Identify: oil = getByName(s, pr, ref r); break; case NIR.Models.PredictMethod.Fitting: oil = getByRate(s, pr, ref r); break; case PredictMethod.Integrate: case NIR.Models.PredictMethod.PLSBind: oil = getByProperties(s, pr, ref r); break; default: break; } GetNIRData(s, oil, ref r); if (oil != null) { r = r.OrderBy(d => (int)d.Table).ToList(); db.OilData.AddObject(new OilData() { SID = s.ID, Data = Serialize.ObjectToByte(r) }); db.SaveChanges(); s.OilData = r; return(true); } else { s.OilData = null; } return(false); } }
// [TestMethod] public void fiiting() { var specbase = new SpecBase(@"F:\3506\15chemometrics\RIPP_DEMO\algorithm\原油测试数据\crude.Lib"); var model = new FittingModel() { Wind = 11, MinSQ = 0.98, TQ = 0.998 }; // var model = new IdentifyModel() { Wind = 11, MinSQ = 0.98, TQ = 0.998 }; model.Filters = new List <IFilter>(); model.Filters.Add(new Sgdiff(21, 2, 2)); model.Filters.Add(new SavitzkyGolay(5)); var xidx = new List <RegionPoint>(); xidx.Add(new RegionPoint(4002, 4702)); xidx.Add(new RegionPoint(5302, 6102)); var varregion = new VarRegionManu(); var argu = varregion.Argus; argu["XaxisRegion"].Value = xidx; argu["Xaxis"].Value = specbase.First().Data.X; varregion.Argus = argu; model.Filters.Add(varregion); model.Filters.Add(new NormPathLength()); model.FiltersForIdentify = Serialize.DeepClone <IList <IFilter> >(model.Filters); var vspecbase = specbase.Clone(); vspecbase.Clear(); foreach (var s in specbase) { if (s.Usage == UsageTypeEnum.Calibrate) { vspecbase.Add(s.Clone()); } } var dd = RIPP.NIR.Data.Preprocesser.Process(model.Filters, vspecbase); var writer = new MatlabMatrixWriter(@"F:\3506\15chemometrics\RIPP_DEMO\src\RIPP\testdata\fit\filterd.mat"); writer.WriteMatrix <double>(dd.GetX(), "filterd"); writer.Close(); var cv = new CrossValidation <FittingResult>(model); var lst = cv.CV(specbase); var allTQ = new DenseVector(specbase.Where(d => d.Usage == UsageTypeEnum.Calibrate).Count()); var allSQ = new DenseVector(specbase.Where(d => d.Usage == UsageTypeEnum.Calibrate).Count()); var allRate = new DenseMatrix(5, specbase.Where(d => d.Usage == UsageTypeEnum.Calibrate).Count()); for (int i = 0; i < lst.Count; i++) { allTQ[i] = lst[i].TQ; allSQ[i] = lst[i].SQ.Min(); var ddd = lst[i].Specs.Select(d => d.Rate); for (int k = 0; k < 5; k++) { if (k >= ddd.Count()) { break; } allRate[k, i] = ddd.ElementAt(k); } } writer = new MatlabMatrixWriter(@"F:\3506\15chemometrics\RIPP_DEMO\src\RIPP\testdata\fit\tq.mat"); writer.WriteMatrix <double>(allTQ.ToColumnMatrix(), "TQ"); writer.Close(); writer = new MatlabMatrixWriter(@"F:\3506\15chemometrics\RIPP_DEMO\src\RIPP\testdata\fit\sq.mat"); writer.WriteMatrix <double>(allSQ.ToColumnMatrix(), "SQ"); writer.Close(); writer = new MatlabMatrixWriter(@"F:\3506\15chemometrics\RIPP_DEMO\src\RIPP\testdata\fit\result.mat"); writer.WriteMatrix <double>(allRate, "allRate"); writer.Close(); }
public List <IntegrateResultItem> Predict(Spectrum spec, bool needFilter = true, int numOfId = 5, int topK = 1) { foreach (var c in this._comps) { c.PredictedValue = 0; } ComponentList idresult = this._comps.Clone(); ComponentList fitresult = this._comps.Clone(); ComponentList pls1result = this._comps.Clone(); ComponentList plsannresult = this._comps.Clone(); IdentifyItem[][] idobj = new IdentifyItem[this._comps.Count][]; FittingResult[] fitobj = new FittingResult[this._comps.Count]; PLS1Result[] pls1obj = new PLS1Result[this._comps.Count]; PLS1Result[] annobj = new PLS1Result[this._comps.Count]; int[] groupidid = new int[this._comps.Count]; int[] groupfitid = new int[this._comps.Count]; double[] idTQ = new double[this._comps.Count]; double[] fitTQ = new double[this._comps.Count]; double[] idSQ = new double[this._comps.Count]; double[] fitSQ = new double[this._comps.Count]; bool[] okid = new bool[this._comps.Count]; bool[] okfit = new bool[this._comps.Count]; bool[] okpls1 = new bool[this._comps.Count]; bool[] okann = new bool[this._comps.Count]; bool[] innerPLs1 = new bool[this._comps.Count]; bool[] innerAnn = new bool[this._comps.Count]; double[] minIdTQ = new double[this._comps.Count]; double[] minFitTQ = new double[this._comps.Count]; double[] minIdSQ = new double[this._comps.Count]; double[] minFitSQ = new double[this._comps.Count]; DateTime dt = DateTime.Now; if (this.IdModels != null && this.IdModels.Count > 0) { var ilst = new List <IdentifyResult>(); foreach (var i in this.IdModels) { ilst.Add(i.Predict(spec, needFilter, numOfId, topK)); } var group = this._idSelectMatrix.Select((d, i) => new { idx = i, d = d }).GroupBy(d => d.d); foreach (var g in group) { var a = new List <IdentifyItem>(); for (int i = 0; i < this.IdModels.Count; i++) { var d = (int)Math.Pow(2, i); if ((d & g.Key) == d) { a.AddRange(ilst[i].Items); } } //找识别出来的 var clst = a.OrderByDescending(d => d.Result).ThenByDescending(d => d.TQ); //取识别结果的明细 var idgobj = clst.Take(10).ToArray();//需要修改 if (clst.Count() > 0) { var idtrue = clst.Where(d => d.Result); foreach (var i in g) { minIdTQ[i.idx] = clst.First().TQ; minIdSQ[i.idx] = clst.First().SQ; var allc = idtrue.Select(d => d.Spec.Components).Where(d => d.Contains(idresult[i.idx].Name)).Select(d => d[idresult[i.idx].Name].ActualValue).Take(numOfId); if (allc.Count() > 0) { okid[i.idx] = true; idresult[i.idx].PredictedValue = allc.Sum() / allc.Count(); } else { var cs = clst.First().Spec.Components; idresult[i.idx].PredictedValue = cs.Contains(idresult[i.idx].Name) ? cs[idresult[i.idx].Name].ActualValue : double.NaN; } idobj[i.idx] = idgobj; groupidid[i.idx] = g.Key; idTQ[i.idx] = this.IdModels.First().TQ; idSQ[i.idx] = this.IdModels.First().MinSQ; } } } } log.InfoFormat("识别库花费{0}s,共{1}个", (DateTime.Now - dt).TotalSeconds, this.IdModels.Count); dt = DateTime.Now; if (this.FitModels != null && this.FitModels.Count > 0) { var group = this._fitSelectMatrix.Select((d, i) => new { idx = i, d = d }).GroupBy(d => d.d); var ilst = new List <FittingResult>(); int gidx = -1; foreach (var g in group) { gidx++; if (this._cacheFitModel == null) { this._cacheFitModel = new List <FittingModel>(); } if (this._cacheFitModel.Count < gidx + 1) { var models = new List <FittingModel>(); for (int i = 0; i < this.FitModels.Count; i++) { var d = (int)Math.Pow(2, i); if ((d & g.Key) == d) { models.Add(this.FitModels[i]); } } if (models.Count == 0) { continue; } var idxmax = models.Select(d => d.SpecLib.Count).Select((d, i) => new { idx = i, d = d }).OrderByDescending(d => d.d).First().idx; var m = Serialize.DeepClone <FittingModel>(models[idxmax]); //合并 DateTime dtn = DateTime.Now; for (int i = 0; i < models.Count; i++) { if (i != idxmax) { m.SpecLib.Merger(models[i].SpecLib); } } log.InfoFormat("merger spend {0}s", (DateTime.Now - dtn).TotalSeconds); dtn = DateTime.Now; this._cacheFitModel.Add(m); } var dddt = DateTime.Now; var fresult = this._cacheFitModel[gidx].Predict(spec, needFilter, numOfId, topK); log.InfoFormat("fit predict spend {0}s", (DateTime.Now - dddt).TotalSeconds); foreach (var i in g) { minFitTQ[i.idx] = fresult.TQ; minFitSQ[i.idx] = fresult.SQ; okfit[i.idx] = fresult.Result; var cs = fresult.FitSpec.Components; fitresult[i.idx].PredictedValue = cs.Contains(fitresult[i.idx].Name) ? cs[fitresult[i.idx].Name].PredictedValue : double.NaN; fitobj[i.idx] = fresult; groupfitid[i.idx] = g.Key; fitTQ[i.idx] = this._cacheFitModel[gidx].TQ; fitSQ[i.idx] = this._cacheFitModel[gidx].MinSQ; } } } log.InfoFormat("拟合库花费{0}s,共{1}个", (DateTime.Now - dt).TotalSeconds, this.FitModels.Count); dt = DateTime.Now; if (this.Pls1Models != null && this.Pls1Models.Count > 0) { foreach (var m in this.Pls1Models) { var idx = pls1result.GetIndex(m.Comp.Name); if (idx >= 0) { var pre = m.Predict(spec, needFilter); pls1result[idx].PredictedValue = pre.Comp.PredictedValue; okpls1[idx] = pre.Comp.State != ComponentStatu.Red; innerPLs1[idx] = pre.Comp.State == ComponentStatu.Pass; pls1obj[idx] = pre; } } } log.InfoFormat("PLS1花费{0}s,共{1}个", (DateTime.Now - dt).TotalSeconds, this.Pls1Models.Count); dt = DateTime.Now; if (this.PlsANNModels != null && this.PlsANNModels.Count > 0) { foreach (var m in this.PlsANNModels) { var idx = plsannresult.GetIndex(m.Comp.Name); if (idx >= 0) { var pre = m.Predict(spec, needFilter); plsannresult[idx].PredictedValue = pre.Comp.PredictedValue; okann[idx] = pre.Comp.State != ComponentStatu.Red; innerAnn[idx] = pre.Comp.State == ComponentStatu.Pass; annobj[idx] = pre; } } } log.InfoFormat("PLSANN花费{0}s,共{1}个", (DateTime.Now - dt).TotalSeconds, this.PlsANNModels.Count); //开始算系数 var result = new List <IntegrateResultItem>(); for (int i = 0; i < this._comps.Count; i++) { var c = this._comps[i]; var r = new IntegrateResultItem() { Comp = c.Clone(), MinFitTQ = minFitTQ[i] == 0 ? double.NaN : minFitTQ[i], MinIdTQ = minIdTQ[i] == 0 ? double.NaN : minIdTQ[i], MinFitSQ = minFitSQ[i] == 0 ? double.NaN : minFitSQ[i], MinIdSQ = minIdSQ[i] == 0 ? double.NaN : minIdSQ[i] }; r.PrimalWID = this._weights[i, 0]; r.PrimalWFit = this._weights[i, 1]; r.PrimalWPLS1 = this._weights[i, 2]; r.PrimalWANN = this._weights[i, 3]; //取系数 r.IdWeight = this._weights[i, 0] > 0 ? this._weights[i, 0] : double.NaN; r.FitWeight = this._weights[i, 1] > 0 ? this._weights[i, 1] : double.NaN; r.Pls1Weight = this._weights[i, 2] > 0 ? this._weights[i, 2] : double.NaN; r.ANNWeight = this._weights[i, 3] > 0 ? this._weights[i, 3] : double.NaN; //取值 r.IdOk = okid[i]; r.FitOk = okfit[i]; r.PLS1Ok = okpls1[i]; r.ANNOk = okann[i]; r.InnerANN = innerAnn[i]; r.InnerPLS = innerPLs1[i]; r.IdValue = idresult[c.Name].PredictedValue; r.FitValue = fitresult[c.Name].PredictedValue; r.Pls1Value = okpls1[i] ? pls1result[c.Name].PredictedValue : double.NaN; r.ANNValue = okann[i] ? plsannresult[c.Name].PredictedValue : double.NaN; r.IdResult = idobj[i]; r.FitResult = fitobj[i]; r.Pls1Result = pls1obj[i]; r.AnnResult = annobj[i]; r.GroupIDID = groupidid[i]; r.GroupFitID = groupfitid[i]; r.IDSQ = idSQ[i]; r.IDTQ = idTQ[i]; r.FitSQ = fitSQ[i]; r.FitTQ = fitTQ[i]; //计算最终结果 bool failid = r.IdResult != null && okid[i] == false; bool failfit = r.FitResult != null && okfit[i] == false; bool failpls1 = r.Pls1Result != null && okpls1[i] == false; bool failann = r.AnnResult != null && okann[i] == false; //修改修改权重 if (failid && (r.FitResult != null || r.Pls1Result != null || r.AnnResult != null)) { r.IdWeight = double.NaN; } if (failfit && (okid[i] || okpls1[i] || okann[i] || r.Pls1Result != null || r.AnnResult != null)) { r.FitWeight = double.NaN; } if (failpls1 && (okid[i] || okfit[i] || okann[i])) { r.Pls1Weight = double.NaN; } if (failann && (okid[i] || okfit[i] || okpls1[i])) { r.ANNWeight = double.NaN; } //求总合 double sumweight = double.Epsilon; if (!double.IsNaN(r.IdWeight)) { sumweight += r.IdWeight; } if (!double.IsNaN(r.FitWeight)) { sumweight += r.FitWeight; } if (!double.IsNaN(r.Pls1Weight)) { sumweight += r.Pls1Weight; } if (!double.IsNaN(r.ANNWeight)) { sumweight += r.ANNWeight; } //乘系统 if (!double.IsNaN(r.IdWeight)) { r.IdWeight = r.IdWeight * (100 / sumweight); } if (!double.IsNaN(r.FitWeight)) { r.FitWeight = r.FitWeight * (100 / sumweight); } if (!double.IsNaN(r.Pls1Weight)) { r.Pls1Weight = r.Pls1Weight * (100 / sumweight); } if (!double.IsNaN(r.ANNWeight)) { r.ANNWeight = r.ANNWeight * (100 / sumweight); } if (r.IdWeight < 0.00001) { r.IdWeight = double.NaN; } if (r.FitWeight < 0.00001) { r.FitWeight = double.NaN; } if (r.Pls1Weight < 0.00001) { r.Pls1Weight = double.NaN; } if (r.ANNWeight < 0.00001) { r.ANNWeight = double.NaN; } double sum = 0; if (!double.IsNaN(r.IdWeight)) { sum += r.IdValue * r.IdWeight; } if (!double.IsNaN(r.FitWeight)) { sum += r.FitValue * r.FitWeight; } if (!double.IsNaN(r.Pls1Weight)) { sum += r.Pls1Value * r.Pls1Weight; } if (!double.IsNaN(r.ANNWeight)) { sum += r.ANNValue * r.ANNWeight; } r.Comp.PredictedValue = sum / 100;//转换百分比 result.Add(r); } return(result); }
public IntegratePropertyResult Predict(Spectrum spec, bool needFilter = true) { IntegratePropertyResult result = new IntegratePropertyResult() { FitRate = this.FitRate, IDRate = this.IDRate, PLS1Rate = this.PLS1Rate, PLSANNRate = this.PLSANNRate, Comp = this._comp.Clone() }; if (this._comp == null)//性质为空,则返回NULL { return(null); } if (this._pls1 != null && this._pls1.Comp.Name == this._comp.Name) { result.PLS1Result = this._pls1.Predict(spec, needFilter); } if (this._plsann != null && this._plsann.Comp.Name == this._comp.Name) { result.PLSANNResult = this._plsann.Predict(spec, needFilter); } //识别 if (this._identify != null && this._identify.Count > 0) { foreach (var i in this._identify) { if (i.SpecLib.Components.Contains(this._comp.Name)) { result.IDResult = BindModel.CombineIdResult(result.IDResult, i.Predict(spec, needFilter)); } } //过滤其它性质 ComponentList clst = new ComponentList(); foreach (var c in result.IDResult.Components) { if (c.Name == this._comp.Name) { clst.Add(c.Clone()); break; } } foreach (var s in result.IDResult.Items) { var c = s.Spec.Components[this._comp.Name].Clone(); s.Spec.Components = new ComponentList(); s.Spec.Components.Add(c); } result.IDResult.Components = clst; } //拟合 if (this._fittings != null && this._fittings.Count > 0) { var fitmodel = Serialize.DeepClone <FittingModel>(this._fittings.First()); for (int i = 1; i < this._fittings.Count; i++) { if (this._fittings[i].SpecLib.Components.Contains(this._comp.Name)) { fitmodel.SpecLib.Merger(this._fittings[i].SpecLib); } } result.FitResult = fitmodel.Predict(spec, needFilter); //过滤其它性质 ComponentList clst = new ComponentList(); foreach (var c in result.FitResult.FitSpec.Components) { if (c.Name == this._comp.Name) { clst.Add(c.Clone()); break; } } result.FitResult.FitSpec.Components = clst; foreach (var s in result.FitResult.Specs) { var c = s.Spec.Components[this._comp.Name].Clone(); s.Spec.Components = new ComponentList(); s.Spec.Components.Add(c); } } return(result); }