Пример #1
0
        /// <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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        /// <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));
        }
Пример #4
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());
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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"
            });
        }