std::pair<unsigned int, Real> ImplicitSystem::sensitivity_solve (const ParameterVector & parameters) { // Log how long the linear solve takes. LOG_SCOPE("sensitivity_solve()", "ImplicitSystem"); // The forward system should now already be solved. // Now assemble the corresponding sensitivity system. if (this->assemble_before_solve) { // Build the Jacobian this->assembly(false, true); this->matrix->close(); // Reset and build the RHS from the residual derivatives this->assemble_residual_derivatives(parameters); } // The sensitivity problem is linear LinearSolver<Number> * linear_solver = this->get_linear_solver(); // Our iteration counts and residuals will be sums of the individual // results std::pair<unsigned int, Real> solver_params = this->get_linear_solve_parameters(); std::pair<unsigned int, Real> totalrval = std::make_pair(0,0.0); // Solve the linear system. SparseMatrix<Number> * pc = this->request_matrix("Preconditioner"); for (auto p : IntRange<unsigned int>(0, parameters.size())) { std::pair<unsigned int, Real> rval = linear_solver->solve (*matrix, pc, this->add_sensitivity_solution(p), this->get_sensitivity_rhs(p), solver_params.second, solver_params.first); totalrval.first += rval.first; totalrval.second += rval.second; } // The linear solver may not have fit our constraints exactly #ifdef LIBMESH_ENABLE_CONSTRAINTS for (auto p : IntRange<unsigned int>(0, parameters.size())) this->get_dof_map().enforce_constraints_exactly (*this, &this->get_sensitivity_solution(p), /* homogeneous = */ true); #endif this->release_linear_solver(linear_solver); return totalrval; }
// Perturb and accumulate dual weighted residuals void HeatSystem::perturb_accumulate_residuals(ParameterVector& parameters_in) { const unsigned int Np = parameters_in.size(); for (unsigned int j=0; j != Np; ++j) { Number old_parameter = *parameters_in[j]; *parameters_in[j] = old_parameter - dp; this->assembly(true, false); this->rhs->close(); UniquePtr<NumericVector<Number> > R_minus = this->rhs->clone(); // The contribution at a single time step would be [f(z;p+dp) - <partialu/partialt, z>(p+dp) - <g(u),z>(p+dp)] * dt // But since we compute the residual already scaled by dt, there is no need for the * dt R_minus_dp += -R_minus->dot(this->get_adjoint_solution(0)); *parameters_in[j] = old_parameter + dp; this->assembly(true, false); this->rhs->close(); UniquePtr<NumericVector<Number> > R_plus = this->rhs->clone(); R_plus_dp += -R_plus->dot(this->get_adjoint_solution(0)); *parameters_in[j] = old_parameter; } }
/// Perform pending updates and divide all parameters by d void average_parameters(ParameterVector& summed_model_params, const ParameterVector& model_params, const ParameterVector& last_model_params, const std::vector<unsigned>& last_param_update, unsigned d) const { for (unsigned p = 0; p < summed_model_params.size(); ++p) { if (d != last_param_update[p]) { unsigned n = d - last_param_update[p]-1; summed_model_params[p] += (n * last_model_params[p]); } summed_model_params[p] /= d; } }
std::pair<unsigned int, Real> EigenSystem::sensitivity_solve (const ParameterVector& parameters) { // make sure that eigensolution is already available libmesh_assert(_n_converged_eigenpairs); // the sensitivity is calculated based on the inner product of the left and // right eigen vectors. // // y^T [A] x - lambda y^T [B] x = 0 // where y and x are the left and right eigenvectors // d lambda/dp = (y^T (d[A]/dp - lambda d[B]/dp) x) / (y^T [B] x) // // the denominator remain constant for all sensitivity calculations. // std::vector<Number> denom(_n_converged_eigenpairs, 0.), sens(_n_converged_eigenpairs, 0.); std::pair<Real, Real> eig_val; AutoPtr< NumericVector<Number> > x_right = NumericVector<Number>::build(this->comm()), x_left = NumericVector<Number>::build(this->comm()), tmp = NumericVector<Number>::build(this->comm()); x_right->init(*solution); x_left->init(*solution); tmp->init(*solution); for (unsigned int i=0; i<_n_converged_eigenpairs; i++) { switch (_eigen_problem_type) { case HEP: // right and left eigenvectors are same // imaginary part of eigenvector for real matrices is zero this->eigen_solver->get_eigenpair(i, *x_right, NULL); denom[i] = x_right->dot(*x_right); // x^H x break; case GHEP: // imaginary part of eigenvector for real matrices is zero this->eigen_solver->get_eigenpair(i, *x_right, NULL); matrix_B->vector_mult(*tmp, *x_right); denom[i] = x_right->dot(*tmp); // x^H B x default: // to be implemented for the non-Hermitian problems libmesh_error(); break; } } for (unsigned int p=0; p<parameters.size(); p++) { // calculate sensitivity of matrix quantities this->assemble_eigensystem_sensitivity(parameters, p); // now calculate sensitivity of each eigenvalue for the parameter for (unsigned int i=0; i<_n_converged_eigenpairs; i++) { eig_val = this->eigen_solver->get_eigenpair(i, *x_right); switch (_eigen_problem_type) { case HEP: matrix_A->vector_mult(*tmp, *x_right); sens[i] = x_right->dot(*tmp); // x^H A' x sens[i] /= denom[i]; // x^H x break; case GHEP: matrix_A->vector_mult(*tmp, *x_right); sens[i] = x_right->dot(*tmp); // x^H A' x matrix_B->vector_mult(*tmp, *x_right); sens[i]-= eig_val.first * x_right->dot(*tmp); // - lambda x^H B' x sens[i] /= denom[i]; // x^H B x break; default: // to be implemented for the non-Hermitian problems libmesh_error(); break; } } } return std::pair<unsigned int, Real> (0, 0.); }
void add_parameters(ParameterVector& summed_model_params, const ParameterVector& model_params) { for (unsigned p = 0; p < summed_model_params.size(); ++p) { summed_model_params[p] += model_params[p]; } }
// Registers a module specific info at the driver void ModuleInfo::registerModule() { m_is_loaded = isLoaded(); cli::ICommandList list = m_module->getCLIInfo(); for (cli::ICommandList::iterator i = list.begin(); i != list.end(); i++) { if (m_is_loaded == false && (*i)->isRequireModule() == true) { // not load the command yet continue; } struct ast_cli_entry* entry = Factory::instance()->getGarbage()->allocEntry(); entry->klkmodnameused = 1; ParameterVector cmds = Utils::getCommands((*i)->getName()); BOOST_ASSERT(cmds.size() > 0 && cmds.size() < (AST_MAX_CMD_LEN - 2)); // ignore module name for service module if (m_module->getID() == srv::MODID) { entry->klkmodnameused = 0; size_t j = 0; for (j = 0; j < AST_MAX_CMD_LEN - 1; j++) { if (j >= cmds.size()) break; entry->cmda[j] = Factory::instance()->getGarbage()->allocData(cmds[j]); } entry->cmda[j] = NULL; } else { /*! Null terminated list of the words of the command */ const std::string modname = m_module->getName(); entry->cmda[0] = Factory::instance()->getGarbage()->allocData(modname); size_t j = 1; for (j = 1; j < AST_MAX_CMD_LEN - 1; j++) { if (j > cmds.size()) break; entry->cmda[j] = Factory::instance()->getGarbage()->allocData(cmds[j - 1]); } entry->cmda[j] = NULL; } /*! Handler for the command (fd for output, # of arguments, argument list). Returns RESULT_SHOWUSAGE for improper arguments */ entry->handler = handle_module; /*! Summary of the command (< 60 characters) */ entry->summary = Factory::instance()->getGarbage()->allocData((*i)->getSummary()); /*! Detailed usage information */ entry->usage = Factory::instance()->getGarbage()->allocData((*i)->getUsage()); /*! Generate a list of possible completions for a given word */ //char *(*generator)(char *line, char *word, int pos, int state); entry->generator = handle_complete; /*! For linking */ entry->next = NULL; /*! For keeping track of usage */ entry->inuse = 0; // KLK specific data entry->klkname = Factory::instance()->getGarbage()->allocData((*i)->getName()); entry->klkmsgid = Factory::instance()->getGarbage()->allocData((*i)->getMessageID()); m_entries.push_back(entry); ast_cli_register(entry); } #if 0 // linking for (EntryList::iterator i = m_entries.begin(); i != m_entries.end(); i++) { // do linking EntryList::iterator next = i; next++; if (next != m_entries.end()) { (*i)->next = *next; } } #endif }