/// Create a submatrix. A submatrix is a view into the parent matrix. /// Lifetime of a submatrix cannot exceed the lifetime of the parent. /// @param M :: The parent matrix. /// @param row :: The first row in the submatrix. /// @param col :: The first column in the submatrix. /// @param nRows :: The number of rows in the submatrix. /// @param nCols :: The number of columns in the submatrix. GSLMatrix::GSLMatrix(const GSLMatrix &M, size_t row, size_t col, size_t nRows, size_t nCols) { if (row + nRows > M.size1() || col + nCols > M.size2()) { throw std::runtime_error("Submatrix exceeds matrix size."); } auto view = gsl_matrix_const_submatrix(M.gsl(), row, col, nRows, nCols); m_matrix = gsl_matrix_alloc(nRows, nCols); gsl_matrix_memcpy(m_matrix, &view.matrix); }
/// Calculate the eigensystem of a symmetric matrix /// @param eigenValues :: Output variable that receives the eigenvalues of this /// matrix. /// @param eigenVectors :: Output variable that receives the eigenvectors of /// this matrix. void GSLMatrix::eigenSystem(GSLVector &eigenValues, GSLMatrix &eigenVectors) { size_t n = size1(); if (n != size2()) { throw std::runtime_error("Matrix eigenSystem: the matrix must be square."); } eigenValues.resize(n); eigenVectors.resize(n, n); auto workspace = gsl_eigen_symmv_alloc(n); gsl_eigen_symmv(gsl(), eigenValues.gsl(), eigenVectors.gsl(), workspace); gsl_eigen_symmv_free(workspace); }
/** * Calculates covariance matrix for fitting function's active parameters. */ void CostFuncFitting::calActiveCovarianceMatrix(GSLMatrix &covar, double epsrel) { // construct the jacobian GSLJacobian J(m_function, m_values->size()); size_t na = this->nParams(); // number of active parameters assert(J.getJ()->size2 == na); covar.resize(na, na); // calculate the derivatives m_function->functionDeriv(*m_domain, J); // let the GSL to compute the covariance matrix gsl_multifit_covar(J.getJ(), epsrel, covar.gsl()); }
/** Executes the algorithm * * @throw runtime_error Thrown if algorithm cannot execute */ void Fit::execConcrete() { std::string ties = getPropertyValue("Ties"); if (!ties.empty()) { m_function->addTies(ties); } std::string contstraints = getPropertyValue("Constraints"); if (!contstraints.empty()) { m_function->addConstraints(contstraints); } // prepare the function for a fit m_function->setUpForFit(); API::FunctionDomain_sptr domain; API::FunctionValues_sptr values; m_domainCreator->createDomain(domain, values); // do something with the function which may depend on workspace m_domainCreator->initFunction(m_function); // get the minimizer std::string minimizerName = getPropertyValue("Minimizer"); API::IFuncMinimizer_sptr minimizer = API::FuncMinimizerFactory::Instance().createMinimizer(minimizerName); // Try to retrieve optional properties int intMaxIterations = getProperty("MaxIterations"); const size_t maxIterations = static_cast<size_t>(intMaxIterations); // get the cost function which must be a CostFuncFitting boost::shared_ptr<CostFuncFitting> costFunc = boost::dynamic_pointer_cast<CostFuncFitting>( API::CostFunctionFactory::Instance().create( getPropertyValue("CostFunction"))); costFunc->setFittingFunction(m_function, domain, values); minimizer->initialize(costFunc, maxIterations); const int64_t nsteps = maxIterations * m_function->estimateNoProgressCalls(); API::Progress prog(this, 0.0, 1.0, nsteps); m_function->setProgressReporter(&prog); // do the fitting until success or iteration limit is reached size_t iter = 0; bool success = false; std::string errorString; g_log.debug("Starting minimizer iteration\n"); while (iter < maxIterations) { g_log.debug() << "Starting iteration " << iter << "\n"; m_function->iterationStarting(); if (!minimizer->iterate(iter)) { errorString = minimizer->getError(); g_log.debug() << "Iteration stopped. Minimizer status string=" << errorString << "\n"; success = errorString.empty() || errorString == "success"; if (success) { errorString = "success"; } break; } prog.report(); m_function->iterationFinished(); ++iter; } g_log.debug() << "Number of minimizer iterations=" << iter << "\n"; minimizer->finalize(); if (iter >= maxIterations) { if (!errorString.empty()) { errorString += '\n'; } errorString += "Failed to converge after " + boost::lexical_cast<std::string>(maxIterations) + " iterations."; } // return the status flag setPropertyValue("OutputStatus", errorString); // degrees of freedom size_t dof = domain->size() - costFunc->nParams(); if (dof == 0) dof = 1; double rawcostfuncval = minimizer->costFunctionVal(); double finalCostFuncVal = rawcostfuncval / double(dof); setProperty("OutputChi2overDoF", finalCostFuncVal); // fit ended, creating output // get the workspace API::Workspace_const_sptr ws = getProperty("InputWorkspace"); bool doCreateOutput = getProperty("CreateOutput"); std::string baseName = getPropertyValue("Output"); if (!baseName.empty()) { doCreateOutput = true; } bool doCalcErrors = getProperty("CalcErrors"); if (doCreateOutput) { doCalcErrors = true; } if (costFunc->nParams() == 0) { doCalcErrors = false; } GSLMatrix covar; if (doCalcErrors) { // Calculate the covariance matrix and the errors. costFunc->calCovarianceMatrix(covar); costFunc->calFittingErrors(covar, rawcostfuncval); } if (doCreateOutput) { copyMinimizerOutput(*minimizer); if (baseName.empty()) { baseName = ws->name(); if (baseName.empty()) { baseName = "Output"; } } baseName += "_"; declareProperty( new API::WorkspaceProperty<API::ITableWorkspace>( "OutputNormalisedCovarianceMatrix", "", Kernel::Direction::Output), "The name of the TableWorkspace in which to store the final covariance " "matrix"); setPropertyValue("OutputNormalisedCovarianceMatrix", baseName + "NormalisedCovarianceMatrix"); Mantid::API::ITableWorkspace_sptr covariance = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); covariance->addColumn("str", "Name"); // set plot type to Label = 6 covariance->getColumn(covariance->columnCount() - 1)->setPlotType(6); // std::vector<std::string> paramThatAreFitted; // used for populating 1st // "name" column for (size_t i = 0; i < m_function->nParams(); i++) { if (m_function->isActive(i)) { covariance->addColumn("double", m_function->parameterName(i)); // paramThatAreFitted.push_back(m_function->parameterName(i)); } } size_t np = m_function->nParams(); size_t ia = 0; for (size_t i = 0; i < np; i++) { if (m_function->isFixed(i)) continue; Mantid::API::TableRow row = covariance->appendRow(); row << m_function->parameterName(i); size_t ja = 0; for (size_t j = 0; j < np; j++) { if (m_function->isFixed(j)) continue; if (j == i) row << 100.0; else { if (!covar.gsl()) { throw std::runtime_error( "There was an error while allocating the (GSL) covariance " "matrix " "which is needed to produce fitting error results."); } row << 100.0 * covar.get(ia, ja) / sqrt(covar.get(ia, ia) * covar.get(ja, ja)); } ++ja; } ++ia; } setProperty("OutputNormalisedCovarianceMatrix", covariance); // create output parameter table workspace to store final fit parameters // including error estimates if derivative of fitting function defined declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>( "OutputParameters", "", Kernel::Direction::Output), "The name of the TableWorkspace in which to store the " "final fit parameters"); setPropertyValue("OutputParameters", baseName + "Parameters"); Mantid::API::ITableWorkspace_sptr result = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); result->addColumn("str", "Name"); // set plot type to Label = 6 result->getColumn(result->columnCount() - 1)->setPlotType(6); result->addColumn("double", "Value"); result->addColumn("double", "Error"); // yErr = 5 result->getColumn(result->columnCount() - 1)->setPlotType(5); for (size_t i = 0; i < m_function->nParams(); i++) { Mantid::API::TableRow row = result->appendRow(); row << m_function->parameterName(i) << m_function->getParameter(i) << m_function->getError(i); } // Add chi-squared value at the end of parameter table Mantid::API::TableRow row = result->appendRow(); #if 1 std::string costfuncname = getPropertyValue("CostFunction"); if (costfuncname == "Rwp") row << "Cost function value" << rawcostfuncval; else row << "Cost function value" << finalCostFuncVal; setProperty("OutputParameters", result); #else row << "Cost function value" << finalCostFuncVal; Mantid::API::TableRow row2 = result->appendRow(); std::string name(getPropertyValue("CostFunction")); name += " value"; row2 << name << rawcostfuncval; #endif setProperty("OutputParameters", result); bool outputParametersOnly = getProperty("OutputParametersOnly"); if (!outputParametersOnly) { const bool unrollComposites = getProperty("OutputCompositeMembers"); bool convolveMembers = existsProperty("ConvolveMembers"); if (convolveMembers) { convolveMembers = getProperty("ConvolveMembers"); } m_domainCreator->separateCompositeMembersInOutput(unrollComposites, convolveMembers); m_domainCreator->createOutputWorkspace(baseName, m_function, domain, values); } } progress(1.0); }
/// Copy constructor /// @param M :: The other matrix. GSLMatrix::GSLMatrix(const GSLMatrix &M) { m_matrix = gsl_matrix_alloc(M.size1(), M.size2()); gsl_matrix_memcpy(m_matrix, M.gsl()); }