/// <summary> /// 計算多變量管制圖的 Tsquare decomposition /// </summary> /// <param name="data"></param> /// <param name="mean"></param> /// <param name="S"></param> /// <returns></returns> public static LinearAlgebra.Matrix <double> T2Decomposition(LinearAlgebra.Matrix <double> data, LinearAlgebra.Matrix <double> mean, LinearAlgebra.Matrix <double> S) { //mean 的 #column = #columns of data = #columns of covariance if (data.ColumnCount != mean.ColumnCount || data.ColumnCount != S.ColumnCount || mean.ColumnCount != S.ColumnCount) { throw new ArgumentException("矩陣的維度無法計算"); } LinearAlgebra.Matrix <double> invS = S.Inverse(); List <double> tsquare = new List <double>(); for (int i = 0; i < data.RowCount; i++) { tsquare.Add(CalculateTSquare(data.Row(i).ToRowMatrix(), mean, invS)); } List <double> decoValue = new List <double>(); for (int c = 0; c < data.ColumnCount; c++) { LinearAlgebra.Matrix <double> subData = data.RemoveColumn(c); LinearAlgebra.Matrix <double> subMean = mean.RemoveColumn(c); LinearAlgebra.Matrix <double> subS = S.RemoveColumn(c).RemoveRow(c); LinearAlgebra.Matrix <double> invSubS = subS.Inverse(); for (int r = 0; r < data.RowCount; r++) { decoValue.Add(tsquare[r] - CalculateTSquare(subData.Row(r).ToRowMatrix(), subMean, invSubS)); } } LinearAlgebra.Matrix <double> m = LinearAlgebra.Matrix <double> .Build.DenseOfColumnMajor(data.RowCount, data.ColumnCount, decoValue); return(m); }
public LinearAlgebra.Vector <double> solveEquations(LinearAlgebra.Matrix <double> stiffnessMatrix, LinearAlgebra.Vector <double> forceVector, List <int> boundaryDofs, List <double> boundaryConstraints) { int nDof = forceVector.Count; // Find all dofs where force is known List <int> allDofs = Enumerable.Range(0, nDof).ToList(); List <int> unknownDofs = allDofs.Except(boundaryDofs).ToList(); // Add the know displacements to the result LinearAlgebra.Vector <double> displacementVector = LinearAlgebra.Vector <double> .Build.Dense(nDof); for (int i = 0; i < boundaryDofs.Count; i++) { displacementVector[boundaryDofs[i]] = boundaryConstraints[i]; } // Pick out part of matrix corresponding to known forces int nrUnknownDofs = unknownDofs.Count; LinearAlgebra.Matrix <double> unknownK = LinearAlgebra.Matrix <double> .Build.Dense(nrUnknownDofs, nrUnknownDofs); LinearAlgebra.Vector <double> knownForces = LinearAlgebra.Vector <double> .Build.Dense(unknownDofs.Count); for (int i = 0; i < unknownDofs.Count; i++) { for (int j = 0; j < unknownDofs.Count; j++) { unknownK[i, j] = stiffnessMatrix[unknownDofs[i], unknownDofs[j]]; } knownForces[i] = forceVector[unknownDofs[i]]; } LinearAlgebra.Matrix <double> unkownKnownK = LinearAlgebra.Matrix <double> .Build.Dense(nrUnknownDofs, boundaryDofs.Count); for (int i = 0; i < unknownDofs.Count; i++) { for (int j = 0; j < boundaryDofs.Count; j++) { unkownKnownK[i, j] = stiffnessMatrix[unknownDofs[i], boundaryDofs[j]]; } knownForces[i] = forceVector[unknownDofs[i]]; } // Solve for the unknown displacements LinearAlgebra.Vector <double> unknownDisplacements = unknownK.Inverse().Multiply(knownForces.Subtract(unkownKnownK.Multiply(LinearAlgebra.Vector <double> .Build.Dense(boundaryConstraints.ToArray())))); // Insert the calculated displacements for (int i = 0; i < unknownDofs.Count; i++) { displacementVector[unknownDofs[i]] = unknownDisplacements[i]; } return(displacementVector); }
/// <summary> /// 計算Tsquare /// </summary> /// <param name="item">a observation</param> /// <param name="mean">mean vector</param> /// <param name="invS">inverse of covariance matrix</param> /// <returns></returns> public static double CalculateTSquare(LinearAlgebra.Matrix <double> item, LinearAlgebra.Matrix <double> mean, LinearAlgebra.Matrix <double> invS) { if (item.ColumnCount != mean.ColumnCount || item.ColumnCount != invS.ColumnCount || mean.ColumnCount != invS.ColumnCount) { throw new ArgumentException("矩陣的維度無法計算"); } LinearAlgebra.Matrix <double> diff = item - mean; var t2 = diff.Multiply(invS).Multiply(diff.Transpose()); return(t2.At(0, 0)); }
/// <summary> /// 計算數列各元素的累積和 /// </summary> /// <param name="x">要處理的陣列,合法的輸入是 double[]</param> /// <returns></returns> public static double[] PartialSum(double[] x) { LinearAlgebra.Vector <double> vx = LinearAlgebra.Double.DenseVector.OfArray(x); int row = vx.Count; int col = row; LinearAlgebra.Matrix <double> lmat = LinearAlgebra.Matrix <double> .Build.Dense(row, col, 1); lmat = lmat.LowerTriangle(); LinearAlgebra.Vector <double> result = lmat.Multiply(vx); return(result.ToArray()); }
public LinearAlgebra.Matrix <double> ComputeStiffnessMatrix() { LinearAlgebra.Matrix <double> K = LinearAlgebra.Matrix <double> .Build.Dense(2, 2); double x1 = Nodes[0].Point.X; double y1 = Nodes[0].Point.Y; double z1 = Nodes[0].Point.Z; double x2 = Nodes[1].Point.X; double y2 = Nodes[1].Point.Y; double z2 = Nodes[1].Point.Z; ElemLength = Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)); K[0, 0] = Area * StiffnessModulus / ElemLength; K[0, 1] = -Area * StiffnessModulus / ElemLength; K[1, 0] = -Area * StiffnessModulus / ElemLength; K[1, 1] = Area * StiffnessModulus / ElemLength; // Tranform to global element stiffness matrix using transformation matrix G double nxx = (x2 - x1) / ElemLength; double nyx = (y2 - y1) / ElemLength; double nzx = (z2 - z1) / ElemLength; G[0, 0] = nxx; G[0, 1] = nyx; G[0, 2] = nzx; G[1, 3] = nxx; G[1, 4] = nyx; G[1, 5] = nzx; LinearAlgebra.Matrix <double> GT = G.Transpose(); LinearAlgebra.Matrix <double> KGlobal = (GT.Multiply(K)).Multiply(G); return(KGlobal); }
protected override void SolveInstance(IGH_DataAccess DA) { // Retrive data from component List <double> A = new List <double>(); List <double> E = new List <double>(); List <Line> lines = new List <Line>(); List <ContstraintNode> rNodes = new List <ContstraintNode>(); List <LoadNode> loadNodes = new List <LoadNode>(); double scaleFactor = 1.0; DA.GetDataList("Line", lines); DA.GetDataList("Area", A); DA.GetDataList("Youngs Modulus", E); DA.GetDataList("Restraint Nodes", rNodes); DA.GetDataList("Load Nodes", loadNodes); DA.GetData("Scale Factor", ref scaleFactor); // The length of A and E must be the same as lines if ((A.Count != E.Count) | (E.Count != lines.Count)) { throw new ArgumentException("Length of A and E must equal length of Line"); } // Create one list to store the nodes and one list to store the bars List <Node> trussNodes = new List <Node>(); List <Bar> trussBars = new List <Bar>(); // Topology matrix to keep track of element dofs List <List <int> > eDof = new List <List <int> >(); // Loop trough each line and create nodes at end points for (int i = 0; i < lines.Count; i++) { Node node1 = new Node(lines[i].From); Node node2 = new Node(lines[i].To); // To keep track if the node is unique bool unique1 = true; bool unique2 = true; // Check if node is unique, if so give it an ID and degress of freedom foreach (Node existingNode in trussNodes) { // If not unique use an already identified node if (node1 == existingNode) { node1 = existingNode; unique1 = false; } if (node2 == existingNode) { node2 = existingNode; unique2 = false; } } // If unique give it an ID if (unique1) { int id_node_1 = trussNodes.Count; node1.ID = id_node_1; node1.Dofs = System.Linq.Enumerable.Range(id_node_1 * 3, 3).ToList(); // Check if any boundary node or load node exist at current node foreach (ContstraintNode rNode in rNodes) { if (rNode == node1) { // Add restraint data node1.ConstraintX = rNode.ConstraintX; node1.ConstraintY = rNode.ConstraintY; node1.ConstraintZ = rNode.ConstraintZ; } } foreach (LoadNode loadNode in loadNodes) { if (loadNode == node1) { // Add force data node1.ForceX = loadNode.ForceX; node1.ForceY = loadNode.ForceY; node1.ForceZ = loadNode.ForceZ; } } // Finally add the node trussNodes.Add(node1); } if (unique2) { int id_node_2 = trussNodes.Count; node2.ID = id_node_2; node2.Dofs = System.Linq.Enumerable.Range(id_node_2 * 3, 3).ToList(); // Check if any boundary node or load node exist at current node foreach (ContstraintNode rNode in rNodes) { if (rNode == node2) { // Add constraint data node2.ConstraintX = rNode.ConstraintX; node2.ConstraintY = rNode.ConstraintY; node2.ConstraintZ = rNode.ConstraintZ; } } foreach (LoadNode loadNode in loadNodes) { if (loadNode == node2) { // Add force data node2.ForceX = loadNode.ForceX; node2.ForceY = loadNode.ForceY; node2.ForceZ = loadNode.ForceZ; } } // Finally add the node trussNodes.Add(node2); } // Create a bar object between the nodes Bar bar = new Bar(node1, node2, A[i], E[i]); trussBars.Add(bar); // Topology matrix List <int> dofs1 = bar.Nodes[0].Dofs; List <int> dofs2 = bar.Nodes[1].Dofs; List <int> eDofRow = new List <int>(); eDofRow.AddRange(dofs1); eDofRow.AddRange(dofs2); eDof.Add(eDofRow); } int nDof = trussNodes.Count * 3; int nElem = eDof.Count; // Loop trough each node and construct a load vector and boundary vector LinearAlgebra.Vector <double> forceVector = LinearAlgebra.Vector <double> .Build.Dense(nDof); List <int> boundaryDofs = new List <int>(); List <double?> boundaryConstraints = new List <double?>(); for (int i = 0; i < trussNodes.Count; i++) { // Load vector forceVector[i * 3] = trussNodes[i].ForceX; forceVector[i * 3 + 1] = trussNodes[i].ForceY; forceVector[i * 3 + 2] = trussNodes[i].ForceZ; // Boundary vector for (int j = 0; j < 3; j++) { if (j == 0 && trussNodes[i].ConstraintX != null) { boundaryDofs.Add(trussNodes[i].Dofs[j]); boundaryConstraints.Add(trussNodes[i].ConstraintX); } else if (j == 1 && trussNodes[i].ConstraintY != null) { boundaryDofs.Add(trussNodes[i].Dofs[j]); boundaryConstraints.Add(trussNodes[i].ConstraintY); } else if (j == 2 && trussNodes[i].ConstraintZ != null) { boundaryDofs.Add(trussNodes[i].Dofs[j]); boundaryConstraints.Add(trussNodes[i].ConstraintZ); } } } // Loop trough each element, compute local stiffness matrix and assemble into global stiffness matrix LinearAlgebra.Matrix <double> K = LinearAlgebra.Matrix <double> .Build.Dense(nDof, nDof); for (int i = 0; i < trussBars.Count; i++) { LinearAlgebra.Matrix <double> KElem = trussBars[i].ComputeStiffnessMatrix(); // Assemble for (int k = 0; k < 6; k++) { for (int l = 0; l < 6; l++) { K[eDof[i][k], eDof[i][l]] = K[eDof[i][k], eDof[i][l]] + KElem[k, l]; } } } // Calculate the displacements Solver solver = new Solver(); LinearAlgebra.Vector <double> displacements = solver.solveEquations(K, forceVector, boundaryDofs, boundaryConstraints.Cast <double>().ToList()); // Save the displacement for each node and calculate the stress in each bar List <double> elemStress = new List <double> { }; for (int i = 0; i < nElem; i++) { double disp1 = displacements[eDof[i][0]]; double disp2 = displacements[eDof[i][1]]; double disp3 = displacements[eDof[i][2]]; double disp4 = displacements[eDof[i][3]]; double disp5 = displacements[eDof[i][4]]; double disp6 = displacements[eDof[i][5]]; Point3d newPoint1 = new Point3d(disp1 * scaleFactor, disp2 * scaleFactor, disp3 * scaleFactor); Point3d newPoint2 = new Point3d(disp4 * scaleFactor, disp5 * scaleFactor, disp6 * scaleFactor); // Translate original points trussBars[i].Nodes[0].Point = trussBars[i].Nodes[0].Point + newPoint1; trussBars[i].Nodes[1].Point = trussBars[i].Nodes[1].Point + newPoint2; // Calculate element stress elemStress.Add(trussBars[i].ComputeStress(new List <double> { disp1, disp2, disp3, disp4, disp5, disp6 })); } // Return the deformed lines List <Line> deformedLines = new List <Line>(); foreach (Bar bar in trussBars) { deformedLines.Add(new Line(bar.Nodes[0].Point, bar.Nodes[1].Point)); } DA.SetDataList("Deformed Truss", deformedLines); DA.SetDataList("Element Stress", elemStress); }
public override void Execute(Mtb.Project proj) { // 將資料匯入 Minitab if (_rawdata == null || _rawdata.Rows.Count == 0) { return; } _rptLst = new List <IRptOutput>(); //重新建立一個分析結果列舉 Mtb.Worksheet ws = proj.Worksheets.Add(1); //新增工作表 Mtblib.Tools.MtbTools.InsertDataTableToMtbWs(_rawdata, ws); //匯入資料至 Minitab List <string> varnames = new List <string>(); List <Mtb.Column> varCols = new List <Mtb.Column>(); //變數的欄位集合 for (int i = 0; i < _rawdata.Columns.Count; i++) { DataColumn col = _rawdata.Columns[i]; switch (col.ColumnName) { case "TIMESTAMP": case "CHART_PARA_INDEX": break; default: varnames.Add(col.ColumnName); varCols.Add(ws.Columns.Item(col.ColumnName)); break; } } foreach (var col in varCols) { if ((int)col.DataType == 3 || col.MissingCount == col.RowCount) { throw new ArgumentNullException(string.Format("[{0}]查無資料-多變量管制圖", col.Name)); } } StringBuilder cmnd = new StringBuilder(); List <TsquareParameters> tmpParaList = new List <TsquareParameters>(); //用於計算 decomposition string[] colIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, 4, Mtblib.Tools.MtbVarType.Column); //Plot point, CL, UCL and Test column // 指定繪圖時需要的欄位變數 Mtb.Column pplotCol = ws.Columns.Item(colIds[0]), clCol = ws.Columns.Item(colIds[1]), uclCol = ws.Columns.Item(colIds[2]), oocCol = ws.Columns.Item(colIds[3]), timeCol = ws.Columns.Item("TIMESTAMP"); // 計算 T2 plot points if (_parameters == null || _parameters.Count == 0) { //自己算的時候需要的變數和子命令 #region Phase I cmnd.AppendLine("macro"); cmnd.AppendLine("myt2calculator x.1-x.p;"); cmnd.AppendLine("variance cov ssiz;"); cmnd.AppendLine("meanvect location; "); cmnd.AppendLine("ppoint t2;"); cmnd.AppendLine("climit cl ucl;"); cmnd.AppendLine("test ooc;"); cmnd.AppendLine("siglevel alpha."); cmnd.AppendLine("mcolumn x.1-x.p t2"); cmnd.AppendLine("mcolumn loc.1-loc.p xx.1-xx.p tmp.1-tmp.3 ooc ucl cl"); cmnd.AppendLine("mconstant ssiz m alpha conf a1 a2 kk"); cmnd.AppendLine("mmatrix location diff cov tdiff invCov"); cmnd.AppendLine("default alpha = 0.0027"); cmnd.AppendLine("rnmiss x.1-x.p tmp.1"); cmnd.AppendLine("copy x.1-x.p xx.1-xx.p;"); cmnd.AppendLine("exclude;"); cmnd.AppendFormat("where \"tmp.1>0\".\r\n"); cmnd.AppendLine("cova xx.1-xx.p cov"); // Get Covariance matrix cmnd.AppendLine("let ssiz = n(xx.1)"); // Get the sample size of covariance calculation, ALSO..THAT IS THE NUMBER OF NONMISSING OBSERVATIONS cmnd.AppendLine("stat x.1-x.p;"); cmnd.AppendLine("mean loc.1-loc.p."); //Get mean vector. /* * Check if there is enough nonmissing observation to calculate control limit under * Tsquare command (m>p+1, where m=#observation, include missing obs, p=#items) * If no, you still need to draw plot points on graph.. * The trick is we given parameters (Mean & Covariance) and given a fake sample size, then * you get t-sq value, becasue we don't need the CL & UCL from Minitab. * (WE USE REGULAR COVARIANCE INSTEAD OF COVARIANCE BY Sullivan & Woodall) * */ cmnd.AppendLine("if(ssiz < p+1)"); cmnd.AppendLine("let kk = p+1"); cmnd.AppendLine("else"); cmnd.AppendLine("copy ssiz kk\r\n"); cmnd.AppendLine("endif"); cmnd.AppendLine("tsquare x.1-x.p 1;"); cmnd.AppendLine("mu loc.1-loc.p;"); cmnd.AppendLine("sigma cov;"); cmnd.AppendLine("number kk;"); cmnd.AppendLine("sampsize tmp.1;"); //Get subgroup size. cmnd.AppendLine("ppoint t2."); //Get Tsquare value. cmnd.AppendLine("copy loc.1-loc.p location"); //Copy column to mean vector cmnd.AppendLine("let m = sum(tmp.1)"); //Get the actual sample size (include missing observations) cmnd.AppendLine("if (m <= p+1)"); // Check if there is enough obs to calc contril limit... cmnd.AppendLine("let cl[m]=miss()"); //no center line cmnd.AppendLine("let ucl[m]=miss()"); //no control limit cmnd.AppendLine("set ooc"); //no ooc cmnd.AppendLine("(0)m"); cmnd.AppendLine("end"); cmnd.AppendLine("else"); cmnd.AppendLine("let conf = 1-alpha"); cmnd.AppendLine("let a1 = p/2"); cmnd.AppendLine("let a2 = (m-p-1)/2"); // Calculate UCL cmnd.AppendLine("set tmp.1"); cmnd.AppendLine("(conf)m"); cmnd.AppendLine("end"); cmnd.AppendLine("invcdf tmp.1 ucl;"); cmnd.AppendLine(" beta a1 a2."); cmnd.AppendLine("let ucl = (m-1)**2/m*ucl"); //Get upper control limit // Calculate CL cmnd.AppendLine("set tmp.1"); cmnd.AppendLine("(0.5)m"); cmnd.AppendLine("end"); cmnd.AppendLine("invcdf tmp.1 cl;"); cmnd.AppendLine(" beta a1 a2."); cmnd.AppendLine("let cl = (m-1)**2/m*cl"); //Get center line cmnd.AppendLine("let ooc = if(t2>ucl and t2<>MISS(),1,0)"); //Get OOC info cmnd.AppendLine("endif"); //刪除所有圖形 cmnd.AppendLine("gmana;"); cmnd.AppendLine("all;"); cmnd.AppendLine("close;"); cmnd.AppendLine("nopr."); cmnd.AppendLine("endmacro"); string macPath = Mtblib.Tools.MtbTools.BuildTemporaryMacro("mytsquare.mac", cmnd.ToString()); string[] matIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, 2, Mtblib.Tools.MtbVarType.Matrix); //紀錄Mean vecot & Covariance matrix string[] constIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, 1, Mtblib.Tools.MtbVarType.Constant); // Sample size of Covariance matrix cmnd.Clear(); cmnd.AppendLine("notitle"); cmnd.AppendLine("brief 0"); cmnd.AppendFormat("%\"{0}\" {1};\r\n", macPath, string.Join(" &\r\n", varCols.Select(x => x.SynthesizedName))); cmnd.AppendFormat("variance {0} {1};\r\n", matIds[0], constIds[0]); cmnd.AppendFormat("meanvect {0};\r\n", matIds[1]); cmnd.AppendFormat("ppoint {0};\r\n", pplotCol.SynthesizedName); cmnd.AppendFormat("climit {0} {1};\r\n", clCol.SynthesizedName, uclCol.SynthesizedName); cmnd.AppendFormat("test {0}.\r\n", oocCol.SynthesizedName); string path = Mtblib.Tools.MtbTools.BuildTemporaryMacro("mymacro.mtb", cmnd.ToString()); proj.ExecuteCommand(string.Format("exec \"{0}\" 1", path), ws); #endregion //取得參數組 TsquareParameters tmpPara = new TsquareParameters(); Mtb.Matrix mat; mat = ws.Matrices.Item(matIds[1]); tmpPara.Mean = LinearAlgebra.Matrix <double> .Build.DenseOfColumnMajor(1, mat.ColumnCount, mat.GetData()); mat = ws.Matrices.Item(matIds[0]); tmpPara.Covariance = LinearAlgebra.Matrix <double> .Build.DenseOfColumnMajor(mat.RowCount, mat.ColumnCount, mat.GetData()); tmpPara.SampleSize = ws.Constants.Item(constIds[0]).GetData(); tmpPara.SubgroupSize = 1; tmpPara.ParaID = null; tmpParaList.Add(tmpPara); } else { //有指定參數的時候 #region Phase II int nParas = ws.Columns.Item("CHART_PARA_INDEX").GetNumDistinctRows(); //宣告多組參數組 cmnd.AppendLine("macro"); cmnd.AppendLine("myt2calculator x.1-x.p;"); cmnd.AppendFormat("variance cov.1-cov.{0} ssiz.1-ssiz.{0};\r\n", nParas); cmnd.AppendFormat("meanvect mvect.1-mvect.{0};\r\n", nParas); cmnd.AppendLine("ppoint t2;"); cmnd.AppendLine("climit cl ucl;"); cmnd.AppendLine("test ooc;"); cmnd.AppendLine("siglevel alpha."); cmnd.AppendLine("mcolumn x.1-x.p xx.1-xx.p xxx.1-xxx.p loc.1-loc.p"); cmnd.AppendLine("mcolumn tmp t2 ucl cl ooc tmpT2 tmpUCL tmpCL tmpOOC"); cmnd.AppendFormat("mmatrix mvect.1-mvect.{0} cov.1-cov.{0}\r\n", nParas); cmnd.AppendFormat("mconstant m histm alpha conf a1 a2 ssiz.1-ssiz.{0} kk\r\n", nParas); cmnd.AppendLine("default alpha = 0.0027"); var _chartparaindex = _rawdata.AsEnumerable() .Select(x => x.Field <string>("CHART_PARA_INDEX")).ToArray(); var _distinctIds = _chartparaindex.Distinct().ToArray(); for (int i = 0; i < _distinctIds.Length; i++) //對每個參數與對應的資料計算 Tsquare 和管制界限 { string id = _distinctIds[i]; cmnd.AppendLine("copy x.1-x.p xx.1-xx.p;"); cmnd.AppendLine("include;"); cmnd.AppendFormat("rows {0}.\r\n", string.Join(" &\r\n", _chartparaindex.Select((x, rowid) => new { Value = x, RowId = rowid + 1 }) .Where(x => x.Value == id).Select(x => x.RowId).ToArray())); #region Set parameter information into Minitab macro TsquareParameters para = new TsquareParameters(); para.Mean = null; para.Covariance = null; para.SampleSize = MISSINGVALUE; para.SubgroupSize = 1; if (id != null) { para = _parameters.Where(x => x.ParaID == id).First(); } if (para.Mean != null) //把已知的 Mean vector 寫入 Minitab { cmnd.AppendLine("read loc.1-loc.p"); cmnd.AppendFormat("{0}\r\n", string.Join(" &\r\n", para.Mean.Enumerate())); cmnd.AppendLine("end"); } else { cmnd.AppendLine("stat xx.1-xx.p;"); cmnd.AppendLine("mean loc.1-loc.p."); } if (para.Covariance != null) //把已知的 Covariance 寫入 Minitab { cmnd.AppendFormat("read {1} {2} cov.{0} \r\n", i + 1, para.Covariance.RowCount, para.Covariance.ColumnCount); List <LinearAlgebra.Vector <double> > valuesByRow = para.Covariance.EnumerateRows().ToList(); for (int r = 0; r < para.Covariance.RowCount; r++) { cmnd.AppendFormat("{0}\r\n", string.Join(" &\r\n", valuesByRow[r])); } cmnd.AppendLine("end"); cmnd.AppendFormat("let ssiz.{0}={1}\r\n", i + 1, para.SampleSize); } else { cmnd.AppendLine("rnmiss xx.1-xx.p tmp"); cmnd.AppendLine("copy xx.1-xx.p xxx.1-xxx.p;"); cmnd.AppendLine("exclud;"); cmnd.AppendFormat("where \"tmp>0\".\r\n"); cmnd.AppendFormat("cova xxx.1-xxx.p cov.{0}\r\n", i + 1); cmnd.AppendFormat("let ssiz.{0} = count(xxx.1)\r\n", i + 1); } #endregion //Tsquare command cmnd.AppendFormat("if(ssiz.{0} < p+1)\r\n", i + 1); cmnd.AppendLine("let kk = p+1"); cmnd.AppendLine("else"); cmnd.AppendFormat("copy ssiz.{0} kk\r\n", i + 1); cmnd.AppendLine("endif"); if (id == null && _chartparaindex.Where(x => x == id).Count() == 1) //如果只有一個觀測值且沒有參數設定 { cmnd.AppendLine("let tmp=1"); cmnd.AppendLine("let tmpT2=miss()"); } else { cmnd.AppendFormat("tsquare xx.1-xx.p {0};\r\n", para.SubgroupSize); cmnd.AppendLine(" mu loc.1-loc.p;"); cmnd.AppendFormat(" sigma cov.{0};\r\n", i + 1); cmnd.AppendLine(" number kk;"); cmnd.AppendLine("sampsize tmp;"); //Get subgroup size. cmnd.AppendLine("ppoint tmpT2."); //Get Tsquare value. } cmnd.AppendFormat("copy loc.1-loc.p mvect.{0}\r\n", i + 1); //Copy column to mean vector /* * Get the value of m which use to calculate UCL, CL. * In phase II, m is the sample size of the data used to calculate historical * covariance matrix. * In phase I, m is the number of observations. * */ cmnd.AppendLine("let m = sum(tmp)"); //Get the actual sample size (include missing data) if (para.Covariance != null) { cmnd.AppendFormat("let histm = ssiz.{0}\r\n", i + 1); } else { cmnd.AppendLine("copy m histm"); } // Calculate control limits if (id == null && _chartparaindex.Where(x => x == id).Count() == 1) { cmnd.AppendLine("let tmpUCL=miss()"); cmnd.AppendLine("let tmpCL=miss()"); } else { cmnd.AppendLine("let conf = 1-alpha"); cmnd.AppendLine("let a1 = p"); cmnd.AppendLine("let a2 = histm"); #region Get UCL cmnd.AppendLine("set tmp"); cmnd.AppendLine("(conf)m"); cmnd.AppendLine("end"); if (id == null) //phase I case { cmnd.AppendLine("invcdf tmp tmpUCL;"); cmnd.AppendLine(" beta a1 a2."); cmnd.AppendLine("let tmpUCL = (m-1)**2/m*tmpUCL"); //Get upper control limit } else //phase II case { cmnd.AppendLine("invcdf tmp tmpUCL;"); cmnd.AppendLine(" f a1 a2."); cmnd.AppendLine("let tmpUCL = p*(histm+1)*(histm-1)/histm/(histm-p)*tmpUCL"); //Get upper control limit } #endregion #region Get CL cmnd.AppendLine("set tmp"); cmnd.AppendLine("(0.5)m"); cmnd.AppendLine("end"); if (id == null) { cmnd.AppendLine("invcdf tmp tmpCL;"); cmnd.AppendLine(" beta a1 a2."); cmnd.AppendLine("let tmpCL = (m-1)**2/m*tmpCL"); //Get upper control limit } else { cmnd.AppendLine("invcdf tmp tmpCL;"); cmnd.AppendLine(" f a1 a2."); cmnd.AppendLine("let tmpCL = p*(histm+1)*(histm-1)/histm/(histm-p)*tmpCL"); //Get center line } #endregion } cmnd.AppendLine("let tmpOOC = if(tmpT2>tmpUCL AND tmpT2<>MISS(),1,0)"); //Get OOC info if (i == 0) { cmnd.AppendLine("copy tmpT2 tmpUCL tmpCL tmpOOC t2 ucl cl ooc"); } else { cmnd.AppendLine("stack (t2 ucl cl ooc) (tmpT2 tmpUCL tmpCL tmpOOC) (t2 ucl cl ooc)"); } } //刪除所有圖形 cmnd.AppendLine("gmana;"); cmnd.AppendLine("all;"); cmnd.AppendLine("close;"); cmnd.AppendLine("nopr."); cmnd.AppendLine("endmacro"); string macPath = Mtblib.Tools.MtbTools.BuildTemporaryMacro("mytsquare.mac", cmnd.ToString()); string[] matMeanIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, nParas, Mtblib.Tools.MtbVarType.Matrix); string[] matCovIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, nParas, Mtblib.Tools.MtbVarType.Matrix); string[] constIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, 1 * nParas, Mtblib.Tools.MtbVarType.Constant); cmnd.Clear(); cmnd.AppendLine("notitle"); cmnd.AppendLine("brief 0"); cmnd.AppendFormat("%\"{0}\" {1};\r\n", macPath, string.Join(" &\r\n", varCols.Select(x => x.SynthesizedName))); cmnd.AppendFormat("variance {0} {1};\r\n", string.Join(" &\r\n", matCovIds), string.Join(" &\r\n", constIds)); cmnd.AppendFormat("meanvect {0};\r\n", string.Join(" &\r\n", matMeanIds)); cmnd.AppendFormat("ppoint {0};\r\n", pplotCol.SynthesizedName); cmnd.AppendFormat("climit {0} {1};\r\n", clCol.SynthesizedName, uclCol.SynthesizedName); cmnd.AppendFormat("test {0}.\r\n", oocCol.SynthesizedName); string path = Mtblib.Tools.MtbTools.BuildTemporaryMacro("mymacro.mtb", cmnd.ToString()); proj.ExecuteCommand(string.Format("exec \"{0}\" 1", path), ws); #endregion //取得參數組 TsquareParameters tmpPara; Mtb.Matrix mat; for (int i = 0; i < _distinctIds.Length; i++) { tmpPara = new TsquareParameters(); tmpPara.ParaID = _distinctIds[i]; mat = ws.Matrices.Item(matMeanIds[i]); tmpPara.Mean = LinearAlgebra.Matrix <double> .Build.DenseOfColumnMajor(mat.RowCount, mat.ColumnCount, mat.GetData()); mat = ws.Matrices.Item(matCovIds[i]); tmpPara.Covariance = LinearAlgebra.Matrix <double> .Build.DenseOfColumnMajor(mat.RowCount, mat.ColumnCount, mat.GetData()); tmpPara.SampleSize = ws.Constants.Item(constIds[i]).GetData(); tmpParaList.Add(tmpPara); } } //繪圖 //會使用 TIMESTAMP, PPOINT, CL, UCL, TEST #region 繪製 T2 Control Chart (TSPLOT) string gpath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("tmp"), "Minitab", string.Format("tsquare_{0}.jpg", _rawdata.TableName)); cmnd.Clear(); cmnd.AppendFormat("fdate {0};\r\n", timeCol.SynthesizedName); cmnd.AppendLine("format(dtyyyy-MM-dd hh:mm)."); cmnd.AppendFormat("tsplot {0} {1} {2};\r\n", pplotCol.SynthesizedName, uclCol.SynthesizedName, clCol.SynthesizedName); cmnd.AppendFormat("gsave \"{0}\";\r\n", gpath); cmnd.AppendLine("repl;"); cmnd.AppendLine("jpeg;"); cmnd.AppendLine("over;"); cmnd.AppendFormat("symb {0};\r\n", oocCol.SynthesizedName); cmnd.AppendLine("type &"); double[] oocData = oocCol.GetData(); if (oocData.Any(x => x == 0)) { cmnd.AppendLine("6 &"); } if (oocData.Any(x => x == 1)) { cmnd.AppendLine("12 &"); } cmnd.AppendLine("0 0 0 0;"); cmnd.AppendLine("size 1;"); cmnd.AppendLine("color &"); if (oocData.Any(x => x == 0)) { cmnd.AppendLine("1 &"); //r17 color 64 } if (oocData.Any(x => x == 1)) { cmnd.AppendLine("2 &"); } cmnd.AppendLine(";"); cmnd.AppendLine("conn;"); cmnd.AppendLine("type 1 1 1;"); cmnd.AppendLine("color 1 2 120;"); //r17 conn:64 cl: 9, climit:8 //cmnd.AppendLine("graph;"); //cmnd.AppendLine("color 22;"); cmnd.AppendLine("nole;"); cmnd.AppendFormat("stamp {0};\r\n", timeCol.SynthesizedName); cmnd.AppendLine("scale 1;"); cmnd.AppendFormat("tick 1:{0}/{1};\r\n", pplotCol.RowCount, pplotCol.RowCount > 35 ? Math.Ceiling((double)pplotCol.RowCount / 35) : 1); cmnd.AppendLine("axla 1;"); cmnd.AppendLine("adis 0;"); cmnd.AppendLine("axla 2;"); cmnd.AppendLine("adis 0;"); string ttlString = string.Join(",", varnames); if (ttlString.Length > 23) { ttlString = ttlString.Substring(0, 20) + "..."; } cmnd.AppendLine("graph 8 4;"); cmnd.AppendFormat("title \"T2管制圖 {0}\";\r\n", ttlString); cmnd.AppendFormat("footn \"更新時間: {0}\";\r\n", DateTime.Now); cmnd.AppendFormat("ZTag \"{0}\";\r\n", "_T2CHART"); cmnd.AppendLine("."); //刪除所有圖形 cmnd.AppendLine("gmana;"); cmnd.AppendLine("all;"); cmnd.AppendLine("close;"); cmnd.AppendLine("nopr."); string t2MacroPath = Mtblib.Tools.MtbTools.BuildTemporaryMacro("myt2macro.mtb", cmnd.ToString()); proj.ExecuteCommand(string.Format("exec \"{0}\" 1", t2MacroPath), ws); #endregion //將檔案轉為二進位陣列 this.Contents.Add(new RptOutput() { OType = MtbOType.GRAPH, OutputInByteArr = File.ReadAllBytes(gpath) }); //計算 Decomposition if (oocData.Any(x => x == 1)) { DataTable tmpDataTable = _rawdata.Copy(); tmpDataTable.Columns.Add("OOC", typeof(int)); for (int r = 0; r < tmpDataTable.Rows.Count; r++) { DataRow dr = tmpDataTable.Rows[r]; dr["OOC"] = oocData[r]; } //建立 Decomposition 的表格 DataTable decoTable = new DataTable(); decoTable.Columns.Add("TIMESTAMP", typeof(DateTime)); foreach (var item in varnames) { decoTable.Columns.Add(item, typeof(double)); } //將OOC的項目值取出 var subData = tmpDataTable.Select("OOC=1").CopyToDataTable(); var oocParaSet = subData.AsEnumerable().Select(dr => dr.Field <string>("CHART_PARA_INDEX")).Distinct().ToArray(); //OOC 的參數組有哪些 foreach (var item in tmpParaList) { if (oocParaSet.Contains(item.ParaID)) //該參數組的觀測值是OOC { //把對應的觀測值轉換成 List<double[]>,其中每個 double[] 是每個 row 的數據 var subsubData = subData.Select(string.Format("CHART_PARA_INDEX {0}", item.ParaID == null ? "IS NULL" : "='" + item.ParaID + "'")) .CopyToDataTable(); var obsArray = subsubData.DefaultView.ToTable(false, varnames.ToArray()) .AsEnumerable().Select(x => x.ItemArray.Select(o => Convert.ToDouble(o)).ToArray()).ToList(); LinearAlgebra.Matrix <double> obs = LinearAlgebra.Matrix <double> .Build.DenseOfRowArrays(obsArray); LinearAlgebra.Matrix <double> t2deco = Tool.T2Decomposition(obs, item.Mean, item.Covariance); var t2decoByRow = t2deco.EnumerateRows().ToArray(); for (int r = 0; r < t2decoByRow.Count(); r++) { DataRow dr = decoTable.NewRow(); object[] o = new object[1 + t2deco.ColumnCount]; t2decoByRow[r].ToArray().CopyTo(o, 1); o[0] = subsubData.Rows[r].Field <DateTime>("TIMESTAMP"); decoTable.Rows.Add(o); } } } cmnd.Clear(); //LinearAlgebra.Matrix<double> obs = LinearAlgebra.Matrix<double>.Build.DenseOfRowArrays(subData); this.Contents.Add(new RptOutput() { OType = MtbOType.TABLE, OutputInByteArr = Tool.ConvertDataSetToByteArray(decoTable) }); } else // 沒有 OOC 就不做 { this.Contents.Add(new RptOutput() { OType = MtbOType.TABLE, OutputInByteArr = null }); } //Console.ReadKey(); }
public override void Execute(Mtb.Project proj) { // 將資料匯入 Minitab if (_rawdata == null || _rawdata.Rows.Count == 0) { throw new ArgumentNullException("查無對應資料"); } _rptLst = new List <IRptOutput>(); //重新建立一個分析結果列舉 proj.Commands.Delete(); proj.Worksheets.Delete(); Mtb.Worksheet ws = proj.Worksheets.Add(1); //新增工作表 Mtblib.Tools.MtbTools.InsertDataTableToMtbWs(_rawdata, ws); //匯入資料至 Minitab List <Mtb.Column> varCols = new List <Mtb.Column>(); //變數的欄位集合 List <Mtb.Column> bkCols = new List <Mtb.Column>(); //斷絲率的集合 Mtb.Column timeCol = null; for (int i = 0; i < _rawdata.Columns.Count; i++) { DataColumn col = _rawdata.Columns[i]; switch (col.ColumnName) { case "TIMESTAMP": timeCol = ws.Columns.Item(col.ColumnName); break; case "RPT_TIMEHOUR": case "GROUP_ID": case "SITE_ID": break; default: if (col.ColumnName.Substring(0, 2) == "BK") { bkCols.Add(ws.Columns.Item(col.ColumnName)); } else { varCols.Add(ws.Columns.Item(col.ColumnName)); } break; } } foreach (var col in bkCols) { if ((int)col.DataType == 3 || col.MissingCount == col.RowCount) { throw new ArgumentNullException(string.Format("[{0}]查無資料", col.Name)); } } foreach (var col in varCols) { if ((int)col.DataType == 3 || col.MissingCount == col.RowCount) { throw new ArgumentNullException(string.Format("[{0}]查無資料", col.Name)); } } StringBuilder cmnd = new StringBuilder(); /* * Create TSPlot * 該圖會將數據於多個平面中顯示(k*1的方式),所以要先設定 Panel 的安排方式 * */ cmnd.AppendLine("notitle"); cmnd.AppendLine("brief 0"); cmnd.AppendFormat("fdate {0};\r\n", timeCol.SynthesizedName); cmnd.AppendLine("format(dtyyyy-MM-dd hh:mm)."); cmnd.AppendFormat("tsplot {0} {1};\r\n", string.Join(" &\r\n", bkCols.Select(x => x.SynthesizedName)), string.Join(" &\r\n", varCols.Select(x => x.SynthesizedName))); double gHeight = 3; //if (varCols.Count > 3) gHeight = Math.Min(30, 4 + ((double)varCols.Count - 3) * 0.8); cmnd.AppendFormat("graph 8 {0};\r\n", gHeight); string gpath_trend = System.IO.Path.Combine(Environment.GetEnvironmentVariable("tmp"), "Minitab", string.Format("trend_{0}.jpg", _rawdata.TableName)); cmnd.AppendFormat("gsave \"{0}\";\r\n", gpath_trend); cmnd.AppendLine("repl;"); cmnd.AppendLine("jpeg;"); //cmnd.AppendLine("panel;"); //cmnd.AppendFormat("rc {0} 1;\r\n", varCols.Count + bkCols.Count); //cmnd.AppendLine("noal;"); //cmnd.AppendLine("label;"); //cmnd.AppendLine(" psize 5;"); cmnd.AppendLine("scale 1;"); cmnd.AppendLine(" psize 8;"); cmnd.AppendLine("grid 1;"); cmnd.AppendLine("axlab 1;"); cmnd.AppendLine("lshow;"); cmnd.AppendLine(" angle 90;"); cmnd.AppendLine("grid 2;"); cmnd.AppendLine("scale 2;"); cmnd.AppendLine(" psize 8;"); if (timeCol != null && (int)timeCol.DataType != 3) { cmnd.AppendFormat("stamp {0};\r\n", timeCol.SynthesizedName); } cmnd.AppendLine("symb;"); cmnd.AppendLine("conn;"); //cmnd.AppendFormat("foot \"建立時間: {0}\";\r\n", DateTime.Now); cmnd.AppendLine("nodt."); //Create Matrix Plot cmnd.AppendFormat("matrixplot ({0})*({1});\r\n", string.Join(" &\r\n", bkCols.Select(x => x.SynthesizedName)), string.Join(" &\r\n", varCols.Select(x => x.SynthesizedName))); double gWidth = 8; if (varCols.Count > 5) { gWidth = Math.Min(30, 8 + ((double)varCols.Count - 5) * 0.8); } cmnd.AppendFormat("graph {0} 5;\r\n", gWidth); string gpath_corr = System.IO.Path.Combine(Environment.GetEnvironmentVariable("tmp"), "Minitab", string.Format("corr_{0}.jpg", _rawdata.TableName)); cmnd.AppendFormat("gsave \"{0}\";\r\n", gpath_corr); cmnd.AppendLine("repl;"); cmnd.AppendLine("jpeg;"); cmnd.AppendLine("scale 1;"); cmnd.AppendLine(" psize 8;"); cmnd.AppendLine("nojitter;"); cmnd.AppendLine("full;"); cmnd.AppendLine("bound;"); cmnd.AppendLine("noal;"); cmnd.AppendLine("regr;"); cmnd.AppendLine("symb;"); cmnd.AppendLine("nodt."); //Calculate correlation coefficient string[] matIds = Mtblib.Tools.MtbTools.CreateVariableStrArray(ws, 1, Mtblib.Tools.MtbVarType.Matrix); cmnd.AppendFormat("corr {0} {1} {2}\r\n", string.Join(" &\r\n", bkCols.Select(x => x.SynthesizedName)), string.Join(" &\r\n", varCols.Select(x => x.SynthesizedName)), string.Join(" &\r\n", matIds) ); //刪除所有圖形 cmnd.AppendLine("gmana;"); cmnd.AppendLine("all;"); cmnd.AppendLine("close;"); cmnd.AppendLine("nopr."); string fpath = Mtblib.Tools.MtbTools.BuildTemporaryMacro("mymacro.mtb", cmnd.ToString()); proj.ExecuteCommand(string.Format("exec \"{0}\" 1", fpath), ws); //將檔案轉為二進位陣列 string _root = System.IO.Path.Combine(Environment.GetEnvironmentVariable("tmp"), "Minitab", string.Format("trend_{0}", _rawdata.TableName)); string _file; for (int i = 0; i < bkCols.Count + varCols.Count; i++) { _file = _root + (i + 1).ToString("D3") + ".jpg"; if (File.Exists(_file)) { this.Contents.Add(new RptOutput() { OType = MtbOType.GRAPH, OutputInByteArr = File.ReadAllBytes(_file), Tag = "Trend" }); } } //if (File.Exists(gpath_trend)) //{ // this.Contents.Add(new RptOutput() // { // OType = MtbOType.GRAPH, // OutputInByteArr = File.ReadAllBytes(gpath_trend), // Tag = "Trend" // }); //} if (File.Exists(gpath_corr)) { this.Contents.Add(new RptOutput() { OType = MtbOType.GRAPH, OutputInByteArr = File.ReadAllBytes(gpath_corr), Tag = "Scatter" }); } //Create Correlation table DataTable corrTable = new DataTable(); corrTable.Columns.Add("熔爐項目", typeof(string)); foreach (Mtb.Column col in bkCols) { corrTable.Columns.Add(col.Name, typeof(double)); } //corrTable.Columns.Add("CorrCoef", typeof(double)); var corrMat = ws.Matrices.Item(matIds[0]).GetData(); //取出 correlation matrix var mBuilder = LinearAlgebra.Matrix <double> .Build; LinearAlgebra.Matrix <double> corM = mBuilder.DenseOfColumnMajor(bkCols.Count + varCols.Count, bkCols.Count + varCols.Count, corrMat); LinearAlgebra.Matrix <double> subCorrMat = corM.SubMatrix(bkCols.Count, varCols.Count, 0, bkCols.Count); string[] labNames = varCols.Select(x => x.Name).ToArray(); List <object> itemArray; DataRow dr; for (int i = 0; i < varCols.Count; i++) { itemArray = new List <object>(); itemArray.Add(labNames[i]); itemArray.AddRange(subCorrMat.Row(i).ToArray().Select(x => (object)Math.Round(x, 3)).ToArray()); //dr = corrTable.NewRow(); //dr.ItemArray = itemArray; corrTable.Rows.Add(itemArray.ToArray()); } //double[] subCorr = new double[varCols.Count]; //double[] corr = corrMat as double[]; //if (corr != null) //{ // Array.Copy(corr, 1, subCorr, 0, varCols.Count); // // DataRow dr; // for (int i = 0; i < subCorr.Length; i++) // { // dr = corrTable.NewRow(); // dr[0] = labNames[i]; // dr[1] = subCorr[i]; // corrTable.Rows.Add(dr); // } //} this.Contents.Add(new RptOutput() { OType = MtbOType.TABLE, OutputInByteArr = Tool.ConvertDataSetToByteArray(corrTable), Tag = "Table" }); }