/*
         *    generic matrix inverse code
         *
         *    @param     x,     input nxn matrix
         *    @param     y,     Output inverted nxn matrix
         *    @param     n,     dimension of square matrix
         *    @returns          false = matrix is Singular, true = matrix inversion successful
         */
        public static bool inverse(float[] x, float[] y, ushort dim)
        {
            switch (dim)
            {
            case 3: return(inverse3x3(x, y));

            case 4: return(inverse4x4(x, y));

            default:
            {
                int info = 0;
                alglib.matinvreport rep = new alglib.matinvreport();
                double[,] input = new double[dim, dim];

                int a = 0;
                foreach (var f in x)
                {
                    input[a / dim, a % dim] = f;
                    a++;
                }

                alglib.rmatrixinverse(ref input, dim, out info, out rep);     // mat_inverse(x, y, dim);

                a = 0;
                foreach (var f in input)
                {
                    y[a] = (float)f;
                    a++;
                }

                return(true);
            }
            }
        }
Exemple #2
0
        public List<string> fit(List<ModeInfo> Modes, bool isQuad, string[] inputFile, FileInfo input, String filepath)
        {
            //string to return
            List<string> output = new List<string>();

            //reads and parses fit file
            string[] fitF = {};
            try
            {
                fitF = FileInfo.FileRead(filepath);
            }
            catch(FileNotFoundException)
            {
                throw new FileNotFoundException("The fit file does not exist.");
            }

            //assign number of eigenvalues to be fit from fitFile
            int nToFit = Convert.ToInt16(fitF[0]);

            //create new Eigenvalue array to store the values from the fit file for each value being fit
            Eigenvalue[] userInput = new Eigenvalue[nToFit];

            //initialize the Eigenvalue array for the fit values from the fit file
            for (int i = 0; i < nToFit; i++)
            {
                if (input.useSeed)
                {
                    userInput[i] = new Eigenvalue(Convert.ToDecimal(fitF[i * 5 + 2]), Convert.ToInt16(fitF[i * 5 + 3]), Convert.ToDecimal(fitF[i * 5 + 4]), Convert.ToDouble(fitF[i * 5 + 1]), FileInfo.TorF(fitF[i * 5 + 5]));
                }
                else // if the seed switch is off, all Lanczos eigenvalues will be labelled as not A1, so we will label all fit file values as not A1
                {
                    userInput[i] = new Eigenvalue(Convert.ToDecimal(fitF[i * 5 + 2]), Convert.ToInt16(fitF[i * 5 + 3]), Convert.ToDecimal(fitF[i * 5 + 4]), Convert.ToDouble(fitF[i * 5 + 1]), false);
                }
            }

            //initializes the X vector, boundary conditions and variable scales
            //xList will contain each parameter being fit
            List<double> xList = new List<double>();

            //the lower bounds for each variable being fit, these are hardcoded
            List<double> bndL = new List<double>();

            //the upper bounds for each variable being fit, these are hardcoded
            List<double> bndU = new List<double>();

            //the scaling values for each variable being fit, these are hardcoded
            List<double> lScale = new List<double>();

            //here I initialize the xList, upper and lower boundaries, and scales for each parameter being fit.
            //for Azeta
            if (input.FitAzeta == true)
            {
                xList.Add(input.Azeta);
                bndL.Add(double.NegativeInfinity);
                bndU.Add(double.PositiveInfinity);
                lScale.Add(1.0);
            }
            //for the origin
            if (input.FitOrigin == true)
            {
                xList.Add(0.0);
                bndL.Add(double.NegativeInfinity);
                bndU.Add(double.PositiveInfinity);
                lScale.Add(50.0);//changed from 200
            }
            //for each mode
            for (int i = 0; i < input.nModes; i++)
            {
                //for Omega
                if (Modes[i].fitOmega == true)
                {
                    xList.Add(Modes[i].modeOmega);
                    bndL.Add(0.0);
                    bndU.Add(double.PositiveInfinity);
                    lScale.Add(50.0);//changed from 100
                }
                //for D
                if (Modes[i].fitD == true)
                {
                    xList.Add(Modes[i].D);
                    bndL.Add(0.0);
                    bndU.Add(double.PositiveInfinity);
                    lScale.Add(3.0);//changed from 10
                }
                //for K
                if (Modes[i].fitK == true)
                {
                    xList.Add(Modes[i].K);
                    bndL.Add(double.NegativeInfinity);
                    bndU.Add(double.PositiveInfinity);
                    lScale.Add(0.5);//changed from 1
                }
                //for wexe
                if (Modes[i].fitWEXE == true)
                {
                    xList.Add(Modes[i].wExe);
                    bndL.Add(double.NegativeInfinity);
                    bndU.Add(double.PositiveInfinity);
                    lScale.Add(10.0);//change from 50
                }
            }
            //then for cross-terms
            if (input.IncludeCrossTerms == true)
            {
                for (int i = 0; i < input.nModes; i++)
                {
                    for (int j = 0; j < input.nModes; j++)
                    {
                        if (input.CrossTermFit[i, j] == true)
                        {
                            xList.Add(input.CrossTermMatrix[i, j]);
                            bndL.Add(double.NegativeInfinity);
                            bndU.Add(double.PositiveInfinity);
                            if (j > i)
                            {
                                lScale.Add(500.0);//scale for bilinear coupling + cross quadratic, changed from 100
                            }
                            if (j == i)
                            {
                                lScale.Add(50.0);//change from 250
                            }
                            else
                            {
                                lScale.Add(50.0);//scale for cross anharmonic, change from 250
                            }
                        }
                    }
                }
            }

            //xVec for minLM optimizer
            double[] xVec = xList.ToArray();

            //Upper/lower boundary arrays for minLM optimizer
            double[] lowBound = bndL.ToArray();
            double[] upBound = bndU.ToArray();

            //scaling array for minLM optimizer
            double[] scale = lScale.ToArray();

            //Generate new Master Object
            //this is an ugly solution to the problem of using the ALGLIB routines since I need to pass a large amount of information
            //to this routine but can only include one object in the arguments.  Therefore, I created the MasterObject just to store
            //this information which I pass to the ALGLIB routine.  Where it's used, it is cast from object to a MasterObject.
            SOCJT run = new SOCJT();
            MasterObject Masterly = new MasterObject();

            //here, if using simple lanczos and wanting evecs, set pVector to false so that they are not calculated each step of the fit
            bool evecs = false;
            if (input.PrintVector && !input.BlockLanczos)
            {
                evecs = true;
                input.PrintVector = false;
            }
            Masterly.Initialize(run, input, Modes, inputFile, isQuad, userInput);

            //initialize and run MinLM algorithm
            double epsg = input.GTol;
            double epsf = input.FTol;
            double epsx = input.XTol;
            int maxits = input.MaxOptimizerSteps;
            alglib.minlmstate state;
            alglib.minlmreport rep;
            //alglib.ndimensional_func func;
            //alglib.ndimensional_grad gradient;
            //alglib.ndimensional_hess hessian;

            alglib.minlmcreatev(userInput.Length, xVec, input.Factor, out state);
            //if (input.calcHessian)
            //{
            //    state.needfgh = true;
            //    //alglib.ndimensional_func func;
            //    //alglib.ndimensional_grad grad;
            //    //alglib.ndimensional_hess HessianMat;
            //    //alglib.minlmoptimize(state, function, null, null, state.repnhess, Masterly);
            //}
            alglib.minlmsetbc(state, lowBound, upBound);
            alglib.minlmsetscale(state, scale);
            alglib.minlmsetcond(state, epsg, epsf, epsx, maxits);
            alglib.minlmsetxrep(state, true);
            //acc = 1, meaning it's on by default.  Just leave that.
            //alglib.minlmsetacctype(state, 0);

            //if (input.calcHessian)
            //{
            //    alglib.minlmoptimize(state, func, gradient, hessian, null, Masterly);
            //}
            alglib.minlmoptimize(state, function, null, Masterly);
            alglib.minlmresults(state, out xVec, out rep);
            int report = rep.terminationtype;
            int iter = rep.iterationscount;

            //this calculates the covariance matrix from the Jacobian using cov[,] = {J^T * J}^-1
            //initialize covariance matrix
            double[,] resultM = new double[state.x.Length, state.x.Length];
            for (int u = 0; u < state.x.Length; u++)
            {
                for (int uu = 0; uu < state.x.Length; uu++)
                {
                    resultM[u, uu] = 0.0;
                }
            }
            //calculate J^T * J and store in resultM
            alglib.rmatrixgemm(state.j.GetLength(1), state.j.GetLength(1), state.j.GetLength(0), 1.0, state.j, 0, 0, 1, state.j, 0, 0, 0, 0.0, ref resultM, 0, 0);
            //take inverse of resultM, replaces resultM
            int invInfo;
            alglib.matinvreport invReport = new alglib.matinvreport();
            alglib.rmatrixinverse(ref resultM, out invInfo, out invReport);
            //now make correlation coefficient matrix
            double[,] corMat = new double[resultM.GetLength(0), resultM.GetLength(0)];
            for (int i = 0; i < resultM.GetLength(0); i++)
            {
                for (int j = 0; j < resultM.GetLength(0); j++)
                {
                    corMat[i, j] = resultM[i, j] / (Math.Sqrt(resultM[i, i] * resultM[j, j]));
                }
            }

            //if eigenvectors are needed when using naive lanczos, run SOCJT routine one more time to calculate them.
            if (evecs && !input.BlockLanczos)
            {
                Console.WriteLine("Calculating eigenvectors.");
                Masterly.nInput.PrintVector = true;
                Masterly.nSoc.SOCJTroutine(Masterly.nModes, Masterly.nIsQuad, Masterly.nInputFile, Masterly.nInput);
                //now assign the lanczosEVectors to those from the SOCJT routine
                lanczosEVectors = Masterly.nSoc.lanczosEVectors;
                basisSet = Masterly.nSoc.basisSet;
            }
            //make output
            soc = Masterly.nSoc;
            output = Masterly.nSoc.outp;
            //add something showing RMS error and parameters for each JT mode
            double[] error = ComparerVec(userInput, Masterly.nSoc.finalList, Masterly.nInput.Origin, true);

            StringBuilder file = new StringBuilder();
            file.AppendLine("Fit report below...");
            file.AppendLine("Termination Type: ");
            if (report == -9)
            {
                file.Append("Derivative correctness check failed");
            }
            if (report == 1)
            {
                file.Append("Relative function improvement is no more than EpsF");
            }
            if (report == 2)
            {
                file.Append("Relative step is no more than EpsX");
            }
            if (report == 4)
            {
                file.Append("Gradient is no more than EpsG");
            }
            if (report == 5)
            {
                file.Append("Maximum number of iterations was exceeded");
            }
            if (report == 7)
            {
                file.Append("Stopping conditions are too stringent, further improvement is impossible");
            }

            file.AppendLine(" ");

            file.AppendLine("Number of iterations: " + Convert.ToString(iter));
            file.AppendLine("Number of times the eigenvalues were calculated: " + Convert.ToString(rep.nfunc));

            file.AppendLine(" ");

            file.AppendLine("A * zeta e = " + Convert.ToString(Masterly.nInput.Azeta));

            /* This is written for data analysis with the NFG program */
            if (input.useNFG == true)
            {
                file.Append("\n" + "NFG_OUTPUT" + "\t");
                for (int ii = 0; ii < Masterly.nInput.nModes; ii++)
                {
                    double JTSE;
                    if (Masterly.nModes[ii].IsAType == true)
                    {
                        JTSE = 0.0;
                    }
                    else
                    {
                        JTSE = Masterly.nModes[ii].D * Masterly.nModes[ii].modeOmega * (Masterly.nModes[ii].K + 1.0);
                    }
                    file.Append(String.Format("{0,7:0.00}", Masterly.nModes[ii].modeOmega) + "\t" + String.Format("{0,4:0.00}", Masterly.nModes[ii].wExe) + "\t" + String.Format("{0,5:0.0000}", Masterly.nModes[ii].D) + "\t" + String.Format("{0,5:0.0000}", Masterly.nModes[ii].K) + "\t" + String.Format("{0,4:0.00}", JTSE) + "\t");
                }
                if (input.IncludeCrossTerms == true)
                {
                    for (int i = 0; i < input.nModes; i++)
                    {
                        for (int j = 0; j < input.nModes; j++)
                        {
                            if (input.CrossTermMatrix[i, j] != 0.0 || input.CrossTermFit[i, j] == true)
                            {
                                if (i < j)
                                {
                                    file.Append(String.Format("{0,10:0.0000}", input.CrossTermMatrix[i, j]) + "\t");
                                }
                                else
                                {
                                    file.Append(String.Format("{0,10:0.0000}", input.CrossTermMatrix[i, j]) + "\t");
                                }
                            }
                        }
                    }
                }
                for (int ll = 0; ll < resultM.GetLength(0); ll++)
                {
                    file.Append(String.Format("{0,10:0.0000}", Math.Sqrt(resultM[ll, ll])) + "\t");
                }
                file.Append(String.Format("{0,10:0.000}", (Math.Sqrt(FitSOCJT.Comparer(userInput, Masterly.nSoc.finalList, Masterly.nInput.Origin) / userInput.Length))));

                file.Append("\n" + "ELEVEL");
                for (int ii = 0; ii < Masterly.nSoc.finalList.Length; ii++)
                {
                    if (Masterly.nSoc.finalList[ii].JBlock == 0.5M)
                    {
                        file.Append("\t" + String.Format("{0,9:0.0000}", Masterly.nSoc.finalList[ii].Evalue));
                    }
                }
                file.Append("\n" + "A1LEVEL");
                for (int ii = 0; ii < Masterly.nSoc.finalList.Length; ii++)
                {
                    if (Masterly.nSoc.finalList[ii].JBlock == 1.5M && Masterly.nSoc.finalList[ii].IsA1 == true)
                    {
                        file.Append("\t" + String.Format("{0,9:0.0000}", Masterly.nSoc.finalList[ii].Evalue));
                    }
                }
                file.Append("\n" + "A2LEVEL");
                for (int ii = 0; ii < Masterly.nSoc.finalList.Length; ii++)
                {
                    if (Masterly.nSoc.finalList[ii].JBlock == 1.5M && Masterly.nSoc.finalList[ii].IsA1 == false)
                    {
                        file.Append("\t" + String.Format("{0,9:0.0000}", Masterly.nSoc.finalList[ii].Evalue));
                    }
                }
                file.AppendLine("\n");
            } // end if useNFG == true

            file.AppendLine("Final Parameters for Each Mode:");
            file.AppendLine("Mode #" + "\t" + "V(min)" + "\t" + "V(max)" + "\t" + "Omega(E)" + "\t" + "wexe" + "\t" + "D" + "\t" + "K" + "\t" + "JTSE" + "\t" + "Omega(A)" + "\t" + "A Type?");
            for (int i = 0; i < Masterly.nInput.nModes; i++)
            {
                double JTSE;
                if (Masterly.nModes[i].IsAType == true)
                {
                    JTSE = 0.0;
                }
                else
                {
                    JTSE = Masterly.nModes[i].D * Masterly.nModes[i].modeOmega * (Masterly.nModes[i].K + 1.0);
                }
                file.AppendLine(Convert.ToString(i + 1) + "\t" + String.Format("{0,4:0}", 0) + "\t" + String.Format("{0,4:0}", Masterly.nModes[i].modeVMax) + "\t" + String.Format("{0,7:0.00}", Masterly.nModes[i].modeOmega) + "\t" + "\t" + String.Format("{0,4:0.00}", Masterly.nModes[i].wExe) + "\t" + String.Format("{0,5:0.0000}", Masterly.nModes[i].D) + "\t" + String.Format("{0,5:0.0000}", Masterly.nModes[i].K) + "\t" + String.Format("{0,4:0.00}", JTSE) + "\t" + String.Format("{0,7:0.00}", Masterly.nModes[i].modeAOmega) + "\t" + "\t" + Convert.ToString(Masterly.nModes[i].IsAType));
            }
            file.AppendLine("  ");
            if (input.FitOrigin == true)
            {
                file.AppendLine("Origin Shift = " + String.Format("{0,8:0.000}", -1.0 * Masterly.nInput.Origin));
            }
            file.AppendLine("  ");
            if (input.IncludeCrossTerms == true)
            {
                for (int i = 0; i < input.nModes; i++)
                {
                    for (int j = 0; j < input.nModes; j++)
                    {
                        if (input.CrossTermMatrix[i, j] != 0.0 || input.CrossTermFit[i, j] == true)
                        {
                            if (i < j)
                            {
                                file.AppendLine("Mode " + Convert.ToString(i + 1) + " Mode " + Convert.ToString(j + 1) + " JT cross-term = " + String.Format("{0,10:0.0000}", input.CrossTermMatrix[i, j]));
                            }
                            else
                            {
                                file.AppendLine("Mode " + Convert.ToString(j + 1) + " Mode " + Convert.ToString(i + 1) + " AT cross-term = " + String.Format("{0,10:0.00}", input.CrossTermMatrix[i, j]));
                            }
                        }
                    }
                }
                file.AppendLine(" ");
            }

            file.AppendLine("Fitting Results:");
            if (input.FitOrigin == true)
            {
                file.AppendLine("Experimental values are shifted by " + String.Format("{0,8:0.000}", Masterly.nInput.Origin) + " wavenumbers.");
            }
            file.AppendLine("FitFile Value" + "\t" + "Calculated Value" + "\t" + "Exp - Calc" + "\t" + "(Exp - Calc)^2");
            for (int i = 0; i < error.Length; i++)
            {
                file.AppendLine(String.Format("{0,13:0.000}", userInput[i].Evalue + Masterly.nInput.Origin) + "\t" + String.Format("{0,13:0.000}", userInput[i].Evalue + Masterly.nInput.Origin - error[i]) + "\t" + "\t" + String.Format("{0,9:0.000}", error[i]) + "\t" + String.Format("{0,11:0.000}", Math.Pow(error[i], 2D)));
            }
            file.AppendLine("  ");
            file.AppendLine("RMS Error = " + String.Format("{0,10:0.000}", (Math.Sqrt(FitSOCJT.Comparer(userInput, Masterly.nSoc.finalList, Masterly.nInput.Origin) / userInput.Length))));
            file.AppendLine("  ");

            int l = 0;
            if (Masterly.nInput.FitAzeta == true)
            {
                file.AppendLine("Azeta StdDev = " + String.Format("{0,10:0.000000}", Math.Sqrt(resultM[l, l])));
                l++;
            }
            if (Masterly.nInput.FitOrigin == true)
            {
                file.AppendLine("Origin StdDev = " + String.Format("{0,10:0.00}", Math.Sqrt(resultM[l, l])));
                l++;
            }
            for (int i = 0; i < Masterly.nInput.nModes; i++)
            {
                if (Masterly.nModes[i].fitOmega == true)
                {
                    file.AppendLine("Mode " + Convert.ToString(i + 1) + " Omega StdDev = " + String.Format("{0,10:0.00}", Math.Sqrt(resultM[l, l])));
                    l++;
                }
                if (Masterly.nModes[i].fitD == true)
                {
                    file.AppendLine("Mode " + Convert.ToString(i + 1) + " D StdDev = " + String.Format("{0,10:0.0000}", Math.Sqrt(resultM[l, l])));
                    l++;
                }
                if (Masterly.nModes[i].fitK == true)
                {
                    file.AppendLine("Mode " + Convert.ToString(i + 1) + " K StdDev = " + String.Format("{0,10:0.0000}", Math.Sqrt(resultM[l, l])));
                    l++;
                }
                if (Masterly.nModes[i].fitWEXE == true)
                {
                    file.AppendLine("Mode " + Convert.ToString(i + 1) + " wexe StdDev = " + String.Format("{0,10:0.00}", Math.Sqrt(resultM[l, l])));
                    l++;
                }
            }
            if (Masterly.nInput.IncludeCrossTerms == true)
            {
                for (int i = 0; i < Masterly.nInput.nModes; i++)
                {
                    for (int h = 0; h < Masterly.nInput.nModes; h++)
                    {
                        if (Masterly.nInput.CrossTermFit[i, h] == true)
                        {
                            if (i < h)
                            {
                                file.AppendLine("Mode " + Convert.ToString(i + 1) + " Mode " + Convert.ToString(h + 1) + " JT Term StdDev = " + String.Format("{0,10:0.0000}", Math.Sqrt(resultM[l, l])));
                                l++;
                            }
                            else
                            {
                                file.AppendLine("Mode " + Convert.ToString(h + 1) + " Mode " + Convert.ToString(i + 1) + " AT Term StdDev = " + String.Format("{0,10:0.00}", Math.Sqrt(resultM[l, l])));
                                l++;
                            }
                        }
                    }
                }
            }
            file.AppendLine(" ");
            file.AppendLine("Correlation coefficient matrix:");
            for (int i = 0; i < resultM.GetLength(0); i++)
            {
                file.AppendLine("");
                file.Append("(");
                for (int j = 0; j < resultM.GetLength(0); j++)
                {
                    if (j != 0)
                    {
                        file.Append(",  ");
                    }
                    file.Append(String.Format("{0,8:0.000}", corMat[i, j]));
                }
                file.Append(")");
            }
            file.AppendLine(" ");
            file.AppendLine(" ");

            output.Add(file.ToString());

            output.AddRange(OutputFile.inputFileMaker(Masterly.nInput, Masterly.nModes));
            return output;
        }