//---------------------------------------------------------------------------------------------- /// Execute the algorithm. void EstimateFitParameters::execConcrete() { auto costFunction = getCostFunctionInitialized(); auto func = costFunction->getFittingFunction(); // Use additional constraints on parameters tied in some way // to the varied parameters to exculde unwanted results. std::vector<std::unique_ptr<IConstraint>> constraints; std::string constraintStr = getProperty("Constraints"); if (!constraintStr.empty()) { Expression expr; expr.parse(constraintStr); expr.toList(); for (auto &term : expr.terms()) { IConstraint *c = ConstraintFactory::Instance().createInitialized(func.get(), term); constraints.push_back(std::unique_ptr<IConstraint>(c)); } } // Ranges to use with random number generators: one for each free parameter. std::vector<std::pair<double, double>> ranges; ranges.reserve(costFunction->nParams()); for (size_t i = 0; i < func->nParams(); ++i) { if (!func->isActive(i)) { continue; } auto constraint = func->getConstraint(i); if (constraint == nullptr) { func->fix(i); continue; } auto boundary = dynamic_cast<Constraints::BoundaryConstraint *>(constraint); if (boundary == nullptr) { throw std::runtime_error("Parameter " + func->parameterName(i) + " must have a boundary constraint. "); } if (!boundary->hasLower()) { throw std::runtime_error("Constraint of " + func->parameterName(i) + " must have a lower bound."); } if (!boundary->hasUpper()) { throw std::runtime_error("Constraint of " + func->parameterName(i) + " must have an upper bound."); } // Use the lower and upper bounds of the constraint to set the range // of a generator with uniform distribution. ranges.push_back(std::make_pair(boundary->lower(), boundary->upper())); } // Number of parameters could have changed costFunction->reset(); if (costFunction->nParams() == 0) { throw std::runtime_error("No parameters are given for which to estimate " "initial values. Set boundary constraints to " "parameters that need to be estimated."); } size_t nSamples = static_cast<int>(getProperty("NSamples")); unsigned int seed = static_cast<int>(getProperty("Seed")); if (getPropertyValue("Type") == "Monte Carlo") { int nOutput = getProperty("NOutputs"); auto outputWorkspaceProp = getPointerToProperty("OutputWorkspace"); if (outputWorkspaceProp->isDefault() || nOutput <= 0) { nOutput = 1; } auto output = runMonteCarlo(*costFunction, ranges, constraints, nSamples, static_cast<size_t>(nOutput), seed); if (!outputWorkspaceProp->isDefault()) { auto table = API::WorkspaceFactory::Instance().createTable(); auto column = table->addColumn("str", "Name"); column->setPlotType(6); for (size_t i = 0; i < output.size(); ++i) { column = table->addColumn("double", std::to_string(i + 1)); column->setPlotType(2); } for (size_t i = 0, ia = 0; i < m_function->nParams(); ++i) { if (m_function->isActive(i)) { TableRow row = table->appendRow(); row << m_function->parameterName(i); for (auto &j : output) { row << j[ia]; } ++ia; } } setProperty("OutputWorkspace", table); } } else { size_t nSelection = static_cast<int>(getProperty("Selection")); size_t nIterations = static_cast<int>(getProperty("NIterations")); runCrossEntropy(*costFunction, ranges, constraints, nSamples, nSelection, nIterations, seed); } bool fixBad = getProperty("FixBadParameters"); if (fixBad) { fixBadParameters(*costFunction, ranges); } }
//---------------------------------------------------------------------------------------------- /// Execute the algorithm. void EstimateFitParameters::execConcrete() { auto costFunction = getCostFunctionProperty(); auto func = costFunction->getFittingFunction(); // Use additional constraints on parameters tied in some way // to the varied parameters to exculde unwanted results. std::vector<std::unique_ptr<IConstraint>> constraints; std::string constraintStr = getProperty("Constraints"); if (!constraintStr.empty()) { Expression expr; expr.parse(constraintStr); expr.toList(); for (auto &term : expr.terms()) { IConstraint *c = ConstraintFactory::Instance().createInitialized(func.get(), term); constraints.push_back(std::unique_ptr<IConstraint>(c)); } } // Ranges to use with random number generators: one for each free parameter. std::vector<std::pair<double, double>> ranges; ranges.reserve(costFunction->nParams()); for (size_t i = 0; i < func->nParams(); ++i) { if (func->isFixed(i)) { continue; } auto constraint = func->getConstraint(i); if (constraint == nullptr) { func->fix(i); continue; } auto boundary = dynamic_cast<Constraints::BoundaryConstraint *>(constraint); if (boundary == nullptr) { throw std::runtime_error("Parameter " + func->parameterName(i) + " must have a boundary constraint. "); } if (!boundary->hasLower()) { throw std::runtime_error("Constraint of " + func->parameterName(i) + " must have a lower bound."); } if (!boundary->hasUpper()) { throw std::runtime_error("Constraint of " + func->parameterName(i) + " must have an upper bound."); } // Use the lower and upper bounds of the constraint to set the range // of a generator with uniform distribution. ranges.push_back(std::make_pair(boundary->lower(), boundary->upper())); } // Number of parameters could have changed costFunction->reset(); if (costFunction->nParams() == 0) { throw std::runtime_error("No parameters are given for which to estimate " "initial values. Set boundary constraints to " "parameters that need to be estimated."); } size_t nSamples = static_cast<int>(getProperty("NSamples")); size_t seed = static_cast<int>(getProperty("Seed")); if (getPropertyValue("Type") == "Monte Carlo") { runMonteCarlo(*costFunction, ranges, constraints, nSamples, seed); } else { size_t nSelection = static_cast<int>(getProperty("Selection")); size_t nIterations = static_cast<int>(getProperty("NIterations")); runCrossEntropy(*costFunction, ranges, constraints, nSamples, nSelection, nIterations, seed); } bool fixBad = getProperty("FixBadParameters"); if (fixBad) { fixBadParameters(*costFunction, ranges); } }