void RBSCMConstruction::evaluate_stability_constant() { START_LOG("evaluate_stability_constant()", "RBSCMConstruction"); // Get current index of C_J const unsigned int j = rb_scm_eval->C_J.size()-1; eigen_solver->set_position_of_spectrum(SMALLEST_REAL); // We assume B is set in system assembly // For coercive problems, B is set to the inner product matrix // For non-coercive time-dependent problems, B is set to the mass matrix // Set matrix A corresponding to mu_star matrix_A->zero(); for(unsigned int q=0; q<get_rb_theta_expansion().get_n_A_terms(); q++) { add_scaled_symm_Aq(q, get_rb_theta_expansion().eval_A_theta(q,get_parameters())); } set_eigensolver_properties(-1); solve(); unsigned int nconv = get_n_converged(); if (nconv != 0) { std::pair<Real, Real> eval = get_eigenpair(0); // ensure that the eigenvalue is real libmesh_assert_less (eval.second, TOLERANCE); // Store the coercivity constant corresponding to mu_star rb_scm_eval->set_C_J_stability_constraint(j,eval.first); libMesh::out << std::endl << "Stability constant for C_J("<<j<<") = " << rb_scm_eval->get_C_J_stability_constraint(j) << std::endl << std::endl; // Compute and store the vector y = (y_1, \ldots, y_Q) for the // eigenvector currently stored in eigen_system.solution. // We use this later to compute the SCM upper bounds. Real norm_B2 = libmesh_real( B_inner_product(*solution, *solution) ); for(unsigned int q=0; q<get_rb_theta_expansion().get_n_A_terms(); q++) { Real norm_Aq2 = libmesh_real( Aq_inner_product(q, *solution, *solution) ); rb_scm_eval->set_SCM_UB_vector(j,q,norm_Aq2/norm_B2); } } else { libMesh::err << "Error: Eigensolver did not converge in evaluate_stability_constant" << std::endl; libmesh_error(); } STOP_LOG("evaluate_stability_constant()", "RBSCMConstruction"); }
Real LaspackVector<T>::min () const { libmesh_assert (this->initialized()); if (!this->size()) return std::numeric_limits<Real>::max(); Real the_min = libmesh_real((*this)(0)); const numeric_index_type n = this->size(); for (numeric_index_type i=1; i<n; i++) the_min = std::min (the_min, libmesh_real((*this)(i))); return the_min; }
Real RBEvaluation::eval_output_dual_norm(unsigned int n, const RBParameters& mu) { Number output_bound_sq = 0.; unsigned int q=0; for(unsigned int q_l1=0; q_l1<rb_theta_expansion->get_n_output_terms(n); q_l1++) { for(unsigned int q_l2=q_l1; q_l2<rb_theta_expansion->get_n_output_terms(n); q_l2++) { Real delta = (q_l1==q_l2) ? 1. : 2.; output_bound_sq += delta * libmesh_real( libmesh_conj(rb_theta_expansion->eval_output_theta(n,q_l1,mu))* rb_theta_expansion->eval_output_theta(n,q_l2,mu) * output_dual_innerprods[n][q] ); q++; } } return libmesh_real(std::sqrt( output_bound_sq )); }
Real EigenSparseVector<T>::min () const { libmesh_assert (this->initialized()); if (!this->size()) return std::numeric_limits<Real>::max(); #ifdef LIBMESH_USE_COMPLEX_NUMBERS Real the_min = libmesh_real((*this)(0)); const numeric_index_type n = this->size(); for (numeric_index_type i=1; i<n; i++) the_min = std::min (the_min, libmesh_real((*this)(i))); return the_min; #else return libmesh_real(_vec.minCoeff()); #endif }
RBParameters RBConstructionBase<Base>::get_params_from_training_set(unsigned int index) { libmesh_assert(training_parameters_initialized); libmesh_assert( (this->get_first_local_training_index() <= index) && (index < this->get_last_local_training_index()) ); RBParameters params; std::map< std::string, NumericVector<Number>* >::const_iterator it = training_parameters.begin(); std::map< std::string, NumericVector<Number>* >::const_iterator it_end = training_parameters.end(); for( ; it != it_end; ++it) { std::string param_name = it->first; Real param_value = libmesh_real( ( *(it->second) )(index) ); params.set_value(param_name, param_value); } return params; }
void NonlinearNeoHookeCurrentConfig::init_for_qp(VectorValue<Gradient> & grad_u, unsigned int qp) { this->current_qp = qp; F.zero(); S.zero(); { RealTensor invF; invF.zero(); for (unsigned int i = 0; i < 3; ++i) for (unsigned int j = 0; j < 3; ++j) { invF(i, j) += libmesh_real(grad_u(i)(j)); } F.add(inv(invF)); libmesh_assert_greater (F.det(), -TOLERANCE); } if (this->calculate_linearized_stiffness) { this->calculate_tangent(); } this->calculate_stress(); }
bool FEMPhysics::eulerian_residual (bool request_jacobian, DiffContext &/*c*/) { // Only calculate a mesh movement residual if it's necessary if (!_mesh_sys) return request_jacobian; libmesh_not_implemented(); #if 0 FEMContext &context = libmesh_cast_ref<FEMContext&>(c); // This function only supports fully coupled mesh motion for now libmesh_assert_equal_to (_mesh_sys, this); unsigned int n_qpoints = (context.get_element_qrule())->n_points(); const unsigned int n_x_dofs = (_mesh_x_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_x_var].size(); const unsigned int n_y_dofs = (_mesh_y_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_y_var].size(); const unsigned int n_z_dofs = (_mesh_z_var == libMesh::invalid_uint) ? 0 : context.dof_indices_var[_mesh_z_var].size(); const unsigned int mesh_xyz_var = n_x_dofs ? _mesh_x_var : (n_y_dofs ? _mesh_y_var : (n_z_dofs ? _mesh_z_var : libMesh::invalid_uint)); // If we're our own _mesh_sys, we'd better be in charge of // at least one coordinate, and we'd better have the same // FE type for all coordinates we are in charge of libmesh_assert_not_equal_to (mesh_xyz_var, libMesh::invalid_uint); libmesh_assert(!n_x_dofs || context.element_fe_var[_mesh_x_var] == context.element_fe_var[mesh_xyz_var]); libmesh_assert(!n_y_dofs || context.element_fe_var[_mesh_y_var] == context.element_fe_var[mesh_xyz_var]); libmesh_assert(!n_z_dofs || context.element_fe_var[_mesh_z_var] == context.element_fe_var[mesh_xyz_var]); const std::vector<std::vector<Real> > &psi = context.element_fe_var[mesh_xyz_var]->get_phi(); for (unsigned int var = 0; var != context.n_vars(); ++var) { // Mesh motion only affects time-evolving variables if (this->is_time_evolving(var)) continue; // The mesh coordinate variables themselves are Lagrangian, // not Eulerian, and no convective term is desired. if (/*_mesh_sys == this && */ (var == _mesh_x_var || var == _mesh_y_var || var == _mesh_z_var)) continue; // Some of this code currently relies on the assumption that // we can pull mesh coordinate data from our own system if (_mesh_sys != this) libmesh_not_implemented(); // This residual should only be called by unsteady solvers: // if the mesh is steady, there's no mesh convection term! UnsteadySolver *unsteady; if (this->time_solver->is_steady()) return request_jacobian; else unsteady = libmesh_cast_ptr<UnsteadySolver*>(this->time_solver.get()); const std::vector<Real> &JxW = context.element_fe_var[var]->get_JxW(); const std::vector<std::vector<Real> > &phi = context.element_fe_var[var]->get_phi(); const std::vector<std::vector<RealGradient> > &dphi = context.element_fe_var[var]->get_dphi(); const unsigned int n_u_dofs = context.dof_indices_var[var].size(); DenseSubVector<Number> &Fu = *context.elem_subresiduals[var]; DenseSubMatrix<Number> &Kuu = *context.elem_subjacobians[var][var]; DenseSubMatrix<Number> *Kux = n_x_dofs ? context.elem_subjacobians[var][_mesh_x_var] : NULL; DenseSubMatrix<Number> *Kuy = n_y_dofs ? context.elem_subjacobians[var][_mesh_y_var] : NULL; DenseSubMatrix<Number> *Kuz = n_z_dofs ? context.elem_subjacobians[var][_mesh_z_var] : NULL; std::vector<Real> delta_x(n_x_dofs, 0.); std::vector<Real> delta_y(n_y_dofs, 0.); std::vector<Real> delta_z(n_z_dofs, 0.); for (unsigned int i = 0; i != n_x_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_x_var][i]; delta_x[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int i = 0; i != n_y_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_y_var][i]; delta_y[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int i = 0; i != n_z_dofs; ++i) { unsigned int j = context.dof_indices_var[_mesh_z_var][i]; delta_z[i] = libmesh_real(this->current_solution(j)) - libmesh_real(unsteady->old_nonlinear_solution(j)); } for (unsigned int qp = 0; qp != n_qpoints; ++qp) { Gradient grad_u = context.interior_gradient(var, qp); RealGradient convection(0.); for (unsigned int i = 0; i != n_x_dofs; ++i) convection(0) += delta_x[i] * psi[i][qp]; for (unsigned int i = 0; i != n_y_dofs; ++i) convection(1) += delta_y[i] * psi[i][qp]; for (unsigned int i = 0; i != n_z_dofs; ++i) convection(2) += delta_z[i] * psi[i][qp]; for (unsigned int i = 0; i != n_u_dofs; ++i) { Number JxWxPhiI = JxW[qp] * phi[i][qp]; Fu(i) += (convection * grad_u) * JxWxPhiI; if (request_jacobian) { Number JxWxPhiI = JxW[qp] * phi[i][qp]; for (unsigned int j = 0; j != n_u_dofs; ++j) Kuu(i,j) += JxWxPhiI * (convection * dphi[j][qp]); Number JxWxPhiIoverDT = JxWxPhiI/this->deltat; Number JxWxPhiIxDUDXoverDT = JxWxPhiIoverDT * grad_u(0); for (unsigned int j = 0; j != n_x_dofs; ++j) (*Kux)(i,j) += JxWxPhiIxDUDXoverDT * psi[j][qp]; Number JxWxPhiIxDUDYoverDT = JxWxPhiIoverDT * grad_u(1); for (unsigned int j = 0; j != n_y_dofs; ++j) (*Kuy)(i,j) += JxWxPhiIxDUDYoverDT * psi[j][qp]; Number JxWxPhiIxDUDZoverDT = JxWxPhiIoverDT * grad_u(2); for (unsigned int j = 0; j != n_z_dofs; ++j) (*Kuz)(i,j) += JxWxPhiIxDUDZoverDT * psi[j][qp]; } } } } #endif // 0 return request_jacobian; }
void FEMSystem::numerical_jacobian (TimeSolverResPtr res, FEMContext &context) { // Logging is done by numerical_elem_jacobian // or numerical_side_jacobian DenseVector<Number> original_residual(context.elem_residual); DenseVector<Number> backwards_residual(context.elem_residual); DenseMatrix<Number> numerical_jacobian(context.elem_jacobian); #ifdef DEBUG DenseMatrix<Number> old_jacobian(context.elem_jacobian); #endif Real numerical_point_h = 0.; if (_mesh_sys == this) numerical_point_h = numerical_jacobian_h * context.elem->hmin(); for (unsigned int j = 0; j != context.dof_indices.size(); ++j) { // Take the "minus" side of a central differenced first derivative Number original_solution = context.elem_solution(j); context.elem_solution(j) -= numerical_jacobian_h; // Make sure to catch any moving mesh terms // FIXME - this could be less ugly Real *coord = NULL; if (_mesh_sys == this) { if (_mesh_x_var != libMesh::invalid_uint) for (unsigned int k = 0; k != context.dof_indices_var[_mesh_x_var].size(); ++k) if (context.dof_indices_var[_mesh_x_var][k] == context.dof_indices[j]) coord = &(const_cast<Elem*>(context.elem)->point(k)(0)); if (_mesh_y_var != libMesh::invalid_uint) for (unsigned int k = 0; k != context.dof_indices_var[_mesh_y_var].size(); ++k) if (context.dof_indices_var[_mesh_y_var][k] == context.dof_indices[j]) coord = &(const_cast<Elem*>(context.elem)->point(k)(1)); if (_mesh_z_var != libMesh::invalid_uint) for (unsigned int k = 0; k != context.dof_indices_var[_mesh_z_var].size(); ++k) if (context.dof_indices_var[_mesh_z_var][k] == context.dof_indices[j]) coord = &(const_cast<Elem*>(context.elem)->point(k)(2)); } if (coord) { // We have enough information to scale the perturbations // here appropriately context.elem_solution(j) = original_solution - numerical_point_h; *coord = libmesh_real(context.elem_solution(j)); } context.elem_residual.zero(); ((*time_solver).*(res))(false, context); #ifdef DEBUG libmesh_assert_equal_to (old_jacobian, context.elem_jacobian); #endif backwards_residual = context.elem_residual; // Take the "plus" side of a central differenced first derivative context.elem_solution(j) = original_solution + numerical_jacobian_h; if (coord) { context.elem_solution(j) = original_solution + numerical_point_h; *coord = libmesh_real(context.elem_solution(j)); } context.elem_residual.zero(); ((*time_solver).*(res))(false, context); #ifdef DEBUG libmesh_assert_equal_to (old_jacobian, context.elem_jacobian); #endif context.elem_solution(j) = original_solution; if (coord) { *coord = libmesh_real(context.elem_solution(j)); for (unsigned int i = 0; i != context.dof_indices.size(); ++i) { numerical_jacobian(i,j) = (context.elem_residual(i) - backwards_residual(i)) / 2. / numerical_point_h; } } else { for (unsigned int i = 0; i != context.dof_indices.size(); ++i) { numerical_jacobian(i,j) = (context.elem_residual(i) - backwards_residual(i)) / 2. / numerical_jacobian_h; } } } context.elem_residual = original_residual; context.elem_jacobian = numerical_jacobian; }
Real RBEvaluation::compute_residual_dual_norm(const unsigned int N) { START_LOG("compute_residual_dual_norm()", "RBEvaluation"); const RBParameters& mu = get_parameters(); // Use the stored representor inner product values // to evaluate the residual norm Number residual_norm_sq = 0.; unsigned int q=0; for(unsigned int q_f1=0; q_f1<rb_theta_expansion->get_n_F_terms(); q_f1++) { for(unsigned int q_f2=q_f1; q_f2<rb_theta_expansion->get_n_F_terms(); q_f2++) { Real delta = (q_f1==q_f2) ? 1. : 2.; residual_norm_sq += delta * libmesh_real( rb_theta_expansion->eval_F_theta(q_f1, mu) * libmesh_conj(rb_theta_expansion->eval_F_theta(q_f2, mu)) * Fq_representor_innerprods[q] ); q++; } } for(unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++) { for(unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++) { for(unsigned int i=0; i<N; i++) { Real delta = 2.; residual_norm_sq += delta * libmesh_real( rb_theta_expansion->eval_F_theta(q_f, mu) * libmesh_conj(rb_theta_expansion->eval_A_theta(q_a, mu)) * libmesh_conj(RB_solution(i)) * Fq_Aq_representor_innerprods[q_f][q_a][i] ); } } } q=0; for(unsigned int q_a1=0; q_a1<rb_theta_expansion->get_n_A_terms(); q_a1++) { for(unsigned int q_a2=q_a1; q_a2<rb_theta_expansion->get_n_A_terms(); q_a2++) { Real delta = (q_a1==q_a2) ? 1. : 2.; for(unsigned int i=0; i<N; i++) { for(unsigned int j=0; j<N; j++) { residual_norm_sq += delta * libmesh_real( libmesh_conj(rb_theta_expansion->eval_A_theta(q_a1, mu)) * rb_theta_expansion->eval_A_theta(q_a2, mu) * libmesh_conj(RB_solution(i)) * RB_solution(j) * Aq_Aq_representor_innerprods[q][i][j] ); } } q++; } } if(libmesh_real(residual_norm_sq) < 0.) { // libMesh::out << "Warning: Square of residual norm is negative " // << "in RBSystem::compute_residual_dual_norm()" << std::endl; // Sometimes this is negative due to rounding error, // but when this occurs the error is on the order of 1.e-10, // so shouldn't affect error bound much... residual_norm_sq = std::abs(residual_norm_sq); } STOP_LOG("compute_residual_dual_norm()", "RBEvaluation"); return std::sqrt( libmesh_real(residual_norm_sq) ); }
// This function solves the tangent system: // [ G_u G_{lambda} ][(du/ds)_new ] = [ 0 ] // [ Theta*(du/ds)_old (dlambda/ds)_old ][(dlambda/ds)_new ] [-N_s] // The solution is given by: // .) Let G_u y = G_lambda, then // .) 2nd row yields: // (dlambda/ds)_new = 1.0 / ( (dlambda/ds)_old - Theta*(du/ds)_old*y ) // .) 1st row yields // (du_ds)_new = -(dlambda/ds)_new * y void ContinuationSystem::solve_tangent() { // We shouldn't call this unless the current tangent already makes sense. libmesh_assert (tangent_initialized); // Set pointer to underlying Newton solver if (!newton_solver) newton_solver = libmesh_cast_ptr<NewtonSolver*> (this->time_solver->diff_solver().get()); // Assemble the system matrix AND rhs, with rhs = G_{\lambda} this->rhs_mode = G_Lambda; // Assemble Residual and Jacobian this->assembly(true, // Residual true); // Jacobian // Not sure if this is really necessary rhs->close(); // Solve G_u*y = G_{\lambda} std::pair<unsigned int, Real> rval = linear_solver->solve(*matrix, *y, *rhs, 1.e-12, // relative linear tolerance 2*newton_solver->max_linear_iterations); // max linear iterations // FIXME: If this doesn't converge at all, the new tangent vector is // going to be really bad... if (!quiet) libMesh::out << "G_u*y = G_{lambda} solver converged at step " << rval.first << " linear tolerance = " << rval.second << "." << std::endl; // Save old solution and parameter tangents for possible use in higher-order // predictor schemes. previous_dlambda_ds = dlambda_ds; *previous_du_ds = *du_ds; // 1.) Previous, probably wrong, technique! // // Solve for the updated d(lambda)/ds // // denom = N_{lambda} - (du_ds)^t y // // = d(lambda)/ds - (du_ds)^t y // Real denom = dlambda_ds - du_ds->dot(*y); // //libMesh::out << "denom=" << denom << std::endl; // libmesh_assert_not_equal_to (denom, 0.0); // dlambda_ds = 1.0 / denom; // if (!quiet) // libMesh::out << "dlambda_ds=" << dlambda_ds << std::endl; // // Compute the updated value of du/ds = -_dlambda_ds * y // du_ds->zero(); // du_ds->add(-dlambda_ds, *y); // du_ds->close(); // 2.) From Brian Carnes' paper... // According to Carnes, y comes from solving G_u * y = -G_{\lambda} y->scale(-1.); const Real ynorm = y->l2_norm(); dlambda_ds = 1. / std::sqrt(1. + Theta_LOCA*Theta_LOCA*Theta*ynorm*ynorm); // Determine the correct sign for dlambda_ds. // We will use delta_u to temporarily compute this sign. *delta_u = *solution; delta_u->add(-1., *previous_u); delta_u->close(); const Real sgn_dlambda_ds = libmesh_real(Theta_LOCA*Theta_LOCA*Theta*y->dot(*delta_u) + (*continuation_parameter-old_continuation_parameter)); if (sgn_dlambda_ds < 0.) { if (!quiet) libMesh::out << "dlambda_ds is negative." << std::endl; dlambda_ds *= -1.; } // Finally, set the new tangent vector, du/ds = dlambda/ds * y. du_ds->zero(); du_ds->add(dlambda_ds, *y); du_ds->close(); if (!quiet) { libMesh::out << "d(lambda)/ds = " << dlambda_ds << std::endl; libMesh::out << "||du_ds|| = " << du_ds->l2_norm() << std::endl; } // Our next solve expects y ~ -du/dlambda, so scale it back by -1 again now. y->scale(-1.); y->close(); }
// This is most of the "guts" of this class. This is where we implement // our custom Newton iterations and perform most of the solves. void ContinuationSystem::continuation_solve() { // Be sure the user has set the continuation parameter pointer if (!continuation_parameter) { libMesh::err << "You must set the continuation_parameter pointer " << "to a member variable of the derived class, preferably in the " << "Derived class's init_data function. This is how the ContinuationSystem " << "updates the continuation parameter." << std::endl; libmesh_error(); } // Use extra precision for all the numbers printed in this function. unsigned int old_precision = libMesh::out.precision(); libMesh::out.precision(16); libMesh::out.setf(std::ios_base::scientific); // We can't start solving the augmented PDE system unless the tangent // vectors have been initialized. This only needs to occur once. if (!tangent_initialized) initialize_tangent(); // Save the old value of -du/dlambda. This will be used after the Newton iterations // to compute the angle between previous tangent vectors. This cosine of this angle is // // tau := abs( (du/d(lambda)_i , du/d(lambda)_{i-1}) / (||du/d(lambda)_i|| * ||du/d(lambda)_{i-1}||) ) // // The scaling factor tau (which should vary between 0 and 1) is used to shrink the step-size ds // when we are approaching a turning point. Note that it can only shrink the step size. *y_old = *y; // Set pointer to underlying Newton solver if (!newton_solver) newton_solver = libmesh_cast_ptr<NewtonSolver*> (this->time_solver->diff_solver().get()); // A pair for catching return values from linear system solves. std::pair<unsigned int, Real> rval; // Convergence flag for the entire arcstep bool arcstep_converged = false; // Begin loop over arcstep reductions. for (unsigned int ns=0; ns<n_arclength_reductions; ++ns) { if (!quiet) { libMesh::out << "Current arclength stepsize, ds_current=" << ds_current << std::endl; libMesh::out << "Current parameter value, lambda=" << *continuation_parameter << std::endl; } // Upon exit from the nonlinear loop, the newton_converged flag // will tell us the convergence status of Newton's method. bool newton_converged = false; // The nonlinear residual before *any* nonlinear steps have been taken. Real nonlinear_residual_firststep = 0.; // The nonlinear residual from the current "k" Newton step, before the Newton step Real nonlinear_residual_beforestep = 0.; // The nonlinear residual from the current "k" Newton step, after the Newton step Real nonlinear_residual_afterstep = 0.; // The linear solver tolerance, can be updated dynamically at each Newton step. Real current_linear_tolerance = 0.; // The nonlinear loop for (newton_step=0; newton_step<newton_solver->max_nonlinear_iterations; ++newton_step) { libMesh::out << "\n === Starting Newton step " << newton_step << " ===" << std::endl; // Set the linear system solver tolerance // // 1.) Set the current linear tolerance based as a multiple of the current residual of the system. // const Real residual_multiple = 1.e-4; // Real current_linear_tolerance = residual_multiple*nonlinear_residual_beforestep; // // But if the current residual isn't small, don't let the solver exit with zero iterations! // if (current_linear_tolerance > 1.) // current_linear_tolerance = residual_multiple; // 2.) Set the current linear tolerance based on the method based on technique of Eisenstat & Walker. if (newton_step==0) { // At first step, only try reducing the residual by a small amount current_linear_tolerance = initial_newton_tolerance;//0.01; } else { // The new tolerance is based on the ratio of the most recent tolerances const Real alp=0.5*(1.+std::sqrt(5.)); const Real gam=0.9; libmesh_assert_not_equal_to (nonlinear_residual_beforestep, 0.0); libmesh_assert_not_equal_to (nonlinear_residual_afterstep, 0.0); current_linear_tolerance = std::min(gam*std::pow(nonlinear_residual_afterstep/nonlinear_residual_beforestep, alp), current_linear_tolerance*current_linear_tolerance ); // Don't let it get ridiculously small!! if (current_linear_tolerance < 1.e-12) current_linear_tolerance = 1.e-12; } if (!quiet) libMesh::out << "Using current_linear_tolerance=" << current_linear_tolerance << std::endl; // Assemble the residual (and Jacobian). rhs_mode = Residual; assembly(true, // Residual true); // Jacobian rhs->close(); // Save the current nonlinear residual. We don't need to recompute the residual unless // this is the first step, since it was already computed as part of the convergence check // at the end of the last loop iteration. if (newton_step==0) { nonlinear_residual_beforestep = rhs->l2_norm(); // Store the residual before any steps have been taken. This will *not* // be updated at each step, and can be used to see if any progress has // been made from the initial residual at later steps. nonlinear_residual_firststep = nonlinear_residual_beforestep; const Real old_norm_u = solution->l2_norm(); libMesh::out << " (before step) ||R||_{L2} = " << nonlinear_residual_beforestep << std::endl; libMesh::out << " (before step) ||R||_{L2}/||u|| = " << nonlinear_residual_beforestep / old_norm_u << std::endl; // In rare cases (very small arcsteps), it's possible that the residual is // already below our absolute linear tolerance. if (nonlinear_residual_beforestep < solution_tolerance) { if (!quiet) libMesh::out << "Initial guess satisfied linear tolerance, exiting with zero Newton iterations!" << std::endl; // Since we go straight from here to the solve of the next tangent, we // have to close the matrix before it can be assembled again. matrix->close(); newton_converged=true; break; // out of Newton iterations, with newton_converged=true } } else { nonlinear_residual_beforestep = nonlinear_residual_afterstep; } // Solve the linear system G_u*z = G // Initial guess? z->zero(); // It seems to be extremely important to zero z here, otherwise the solver quits early. z->close(); // It's possible that we have selected the current_linear_tolerance so large that // a guess of z=zero yields a linear system residual |Az + R| small enough that the // linear solver exits in zero iterations. If this happens, we will reduce the // current_linear_tolerance until the linear solver does at least 1 iteration. do { rval = linear_solver->solve(*matrix, *z, *rhs, //1.e-12, current_linear_tolerance, newton_solver->max_linear_iterations); // max linear iterations if (rval.first==0) { if (newton_step==0) { libMesh::out << "Repeating initial solve with smaller linear tolerance!" << std::endl; current_linear_tolerance *= initial_newton_tolerance; // reduce the linear tolerance to force the solver to do some work } else { // We shouldn't get here ... it means the linear solver did no work on a Newton // step other than the first one. If this happens, we need to think more about our // tolerance selection. libmesh_error(); } } } while (rval.first==0); if (!quiet) libMesh::out << " G_u*z = G solver converged at step " << rval.first << " linear tolerance = " << rval.second << "." << std::endl; // Sometimes (I am not sure why) the linear solver exits after zero iterations. // Perhaps it is hitting PETSc's divergence tolerance dtol??? If this occurs, // we should break out of the Newton iteration loop because nothing further is // going to happen... Of course if the tolerance is already small enough after // zero iterations (how can this happen?!) we should not quit. if ((rval.first == 0) && (rval.second > current_linear_tolerance*nonlinear_residual_beforestep)) { if (!quiet) libMesh::out << "Linear solver exited in zero iterations!" << std::endl; // Try to find out the reason for convergence/divergence linear_solver->print_converged_reason(); break; // out of Newton iterations } // Note: need to scale z by -1 since our code always solves Jx=R // instead of Jx=-R. z->scale(-1.); z->close(); // Assemble the G_Lambda vector, skip residual. rhs_mode = G_Lambda; // Assemble both rhs and Jacobian assembly(true, // Residual false); // Jacobian // Not sure if this is really necessary rhs->close(); const Real yrhsnorm=rhs->l2_norm(); if (yrhsnorm == 0.0) { libMesh::out << "||G_Lambda|| = 0" << std::endl; libmesh_error(); } // We select a tolerance for the y-system which is based on the inexact Newton // tolerance but scaled by an extra term proportional to the RHS (which is not -> 0 in this case) const Real ysystemtol=current_linear_tolerance*(nonlinear_residual_beforestep/yrhsnorm); if (!quiet) libMesh::out << "ysystemtol=" << ysystemtol << std::endl; // Solve G_u*y = G_{\lambda} // FIXME: Initial guess? This is really a solve for -du/dlambda so we could try // initializing it with the latest approximation to that... du/dlambda ~ du/ds * ds/dlambda //*y = *solution; //y->add(-1., *previous_u); //y->scale(-1. / (*continuation_parameter - old_continuation_parameter)); // Be careful of divide by zero... //y->close(); // const unsigned int max_attempts=1; // unsigned int attempt=0; // do // { // if (!quiet) // libMesh::out << "Trying to solve tangent system, attempt " << attempt << std::endl; rval = linear_solver->solve(*matrix, *y, *rhs, //1.e-12, ysystemtol, newton_solver->max_linear_iterations); // max linear iterations if (!quiet) libMesh::out << " G_u*y = G_{lambda} solver converged at step " << rval.first << ", linear tolerance = " << rval.second << "." << std::endl; // Sometimes (I am not sure why) the linear solver exits after zero iterations. // Perhaps it is hitting PETSc's divergence tolerance dtol??? If this occurs, // we should break out of the Newton iteration loop because nothing further is // going to happen... if ((rval.first == 0) && (rval.second > ysystemtol)) { if (!quiet) libMesh::out << "Linear solver exited in zero iterations!" << std::endl; break; // out of Newton iterations } // ++attempt; // } while ((attempt<max_attempts) && (rval.first==newton_solver->max_linear_iterations)); // Compute N, the residual of the arclength constraint eqn. // Note 1: N(u,lambda,s) := (u-u_{old}, du_ds) + (lambda-lambda_{old}, dlambda_ds) - _ds // We temporarily use the delta_u vector as a temporary vector for this calculation. *delta_u = *solution; delta_u->add(-1., *previous_u); // First part of the arclength constraint const Number N1 = Theta_LOCA*Theta_LOCA*Theta*delta_u->dot(*du_ds); const Number N2 = ((*continuation_parameter) - old_continuation_parameter)*dlambda_ds; const Number N3 = ds_current; if (!quiet) { libMesh::out << " N1=" << N1 << std::endl; libMesh::out << " N2=" << N2 << std::endl; libMesh::out << " N3=" << N3 << std::endl; } // The arclength constraint value const Number N = N1+N2-N3; if (!quiet) libMesh::out << " N=" << N << std::endl; const Number duds_dot_z = du_ds->dot(*z); const Number duds_dot_y = du_ds->dot(*y); //libMesh::out << "duds_dot_z=" << duds_dot_z << std::endl; //libMesh::out << "duds_dot_y=" << duds_dot_y << std::endl; //libMesh::out << "dlambda_ds=" << dlambda_ds << std::endl; const Number delta_lambda_numerator = -(N + Theta_LOCA*Theta_LOCA*Theta*duds_dot_z); const Number delta_lambda_denominator = (dlambda_ds - Theta_LOCA*Theta_LOCA*Theta*duds_dot_y); libmesh_assert_not_equal_to (delta_lambda_denominator, 0.0); // Now, we are ready to compute the step delta_lambda const Number delta_lambda_comp = delta_lambda_numerator / delta_lambda_denominator; // Lambda is real-valued const Real delta_lambda = libmesh_real(delta_lambda_comp); // Knowing delta_lambda, we are ready to update delta_u // delta_u = z - delta_lambda*y delta_u->zero(); delta_u->add(1., *z); delta_u->add(-delta_lambda, *y); delta_u->close(); // Update the system solution and the continuation parameter. solution->add(1., *delta_u); solution->close(); *continuation_parameter += delta_lambda; // Did the Newton step actually reduce the residual? rhs_mode = Residual; assembly(true, // Residual false); // Jacobian rhs->close(); nonlinear_residual_afterstep = rhs->l2_norm(); // In a "normal" Newton step, ||du||/||R|| > 1 since the most recent // step is where you "just were" and the current residual is where // you are now. It can occur that ||du||/||R|| < 1, but these are // likely not good cases to attempt backtracking (?). const Real norm_du_norm_R = delta_u->l2_norm() / nonlinear_residual_afterstep; if (!quiet) libMesh::out << " norm_du_norm_R=" << norm_du_norm_R << std::endl; // Factor to decrease the stepsize by for backtracking Real newton_stepfactor = 1.; const bool attempt_backtracking = (nonlinear_residual_afterstep > solution_tolerance) && (nonlinear_residual_afterstep > nonlinear_residual_beforestep) && (n_backtrack_steps>0) && (norm_du_norm_R > 1.) ; // If residual is not reduced, do Newton back tracking. if (attempt_backtracking) { if (!quiet) libMesh::out << "Newton step did not reduce residual." << std::endl; // back off the previous step. solution->add(-1., *delta_u); solution->close(); *continuation_parameter -= delta_lambda; // Backtracking: start cutting the Newton stepsize by halves until // the new residual is actually smaller... for (unsigned int backtrack_step=0; backtrack_step<n_backtrack_steps; ++backtrack_step) { newton_stepfactor *= 0.5; if (!quiet) libMesh::out << "Shrinking step size by " << newton_stepfactor << std::endl; // Take fractional step solution->add(newton_stepfactor, *delta_u); solution->close(); *continuation_parameter += newton_stepfactor*delta_lambda; rhs_mode = Residual; assembly(true, // Residual false); // Jacobian rhs->close(); nonlinear_residual_afterstep = rhs->l2_norm(); if (!quiet) libMesh::out << "At shrink step " << backtrack_step << ", nonlinear_residual_afterstep=" << nonlinear_residual_afterstep << std::endl; if (nonlinear_residual_afterstep < nonlinear_residual_beforestep) { if (!quiet) libMesh::out << "Backtracking succeeded!" << std::endl; break; // out of backtracking loop } else { // Back off that step solution->add(-newton_stepfactor, *delta_u); solution->close(); *continuation_parameter -= newton_stepfactor*delta_lambda; } // Save a copy of the solution from before the Newton step. //AutoPtr<NumericVector<Number> > prior_iterate = solution->clone(); } } // end if (attempte_backtracking) // If we tried backtracking but the residual is still not reduced, print message. if ((attempt_backtracking) && (nonlinear_residual_afterstep > nonlinear_residual_beforestep)) { //libMesh::err << "Backtracking failed." << std::endl; libMesh::out << "Backtracking failed." << std::endl; // 1.) Quit, exit program. //libmesh_error(); // 2.) Continue with last newton_stepfactor if (newton_step<3) { solution->add(newton_stepfactor, *delta_u); solution->close(); *continuation_parameter += newton_stepfactor*delta_lambda; if (!quiet) libMesh::out << "Backtracking could not reduce residual ... continuing anyway!" << std::endl; } // 3.) Break out of Newton iteration loop with newton_converged = false, // reduce the arclength stepsize, and try again. else { break; // out of Newton iteration loop, with newton_converged=false } } // Another type of convergence check: suppose the residual has not been reduced // from its initial value after half of the allowed Newton steps have occurred. // In our experience, this typically means that it isn't going to converge and // we could probably save time by dropping out of the Newton iteration loop and // trying a smaller arcstep. if (this->newton_progress_check) { if ((nonlinear_residual_afterstep > nonlinear_residual_firststep) && (newton_step+1 > static_cast<unsigned int>(0.5*newton_solver->max_nonlinear_iterations))) { libMesh::out << "Progress check failed: the current residual: " << nonlinear_residual_afterstep << ", is\n" << "larger than the initial residual, and half of the allowed\n" << "number of Newton iterations have elapsed.\n" << "Exiting Newton iterations with converged==false." << std::endl; break; // out of Newton iteration loop, newton_converged = false } } // Safety check: Check the current continuation parameter against user-provided min-allowable parameter value if (*continuation_parameter < min_continuation_parameter) { libMesh::out << "Continuation parameter fell below min-allowable value." << std::endl; // libmesh_error(); break; // out of Newton iteration loop, newton_converged = false } // Safety check: Check the current continuation parameter against user-provided max-allowable parameter value if ( (max_continuation_parameter != 0.0) && (*continuation_parameter > max_continuation_parameter) ) { libMesh::out << "Current continuation parameter value: " << *continuation_parameter << " exceeded max-allowable value." << std::endl; // libmesh_error(); break; // out of Newton iteration loop, newton_converged = false } // Check the convergence of the parameter and the solution. If they are small // enough, we can break out of the Newton iteration loop. const Real norm_delta_u = delta_u->l2_norm(); const Real norm_u = solution->l2_norm(); libMesh::out << " delta_lambda = " << delta_lambda << std::endl; libMesh::out << " newton_stepfactor*delta_lambda = " << newton_stepfactor*delta_lambda << std::endl; libMesh::out << " lambda_current = " << *continuation_parameter << std::endl; libMesh::out << " ||delta_u|| = " << norm_delta_u << std::endl; libMesh::out << " ||delta_u||/||u|| = " << norm_delta_u / norm_u << std::endl; // Evaluate the residual at the current Newton iterate. We don't want to detect // convergence due to a small Newton step when the residual is still not small. rhs_mode = Residual; assembly(true, // Residual false); // Jacobian rhs->close(); const Real norm_residual = rhs->l2_norm(); libMesh::out << " ||R||_{L2} = " << norm_residual << std::endl; libMesh::out << " ||R||_{L2}/||u|| = " << norm_residual / norm_u << std::endl; // FIXME: The norm_delta_u tolerance (at least) should be relative. // It doesn't make sense to converge a solution whose size is ~ 10^5 to // a tolerance of 1.e-6. Oh, and we should also probably check the // (relative) size of the residual as well, instead of just the step. if ((std::abs(delta_lambda) < continuation_parameter_tolerance) && //(norm_delta_u < solution_tolerance) && // This is a *very* strict criterion we can probably skip (norm_residual < solution_tolerance)) { if (!quiet) libMesh::out << "Newton iterations converged!" << std::endl; newton_converged = true; break; // out of Newton iterations } } // end nonlinear loop if (!newton_converged) { libMesh::out << "Newton iterations of augmented system did not converge!" << std::endl; // Reduce ds_current, recompute the solution and parameter, and continue to next // arcstep, if there is one. ds_current *= 0.5; // Go back to previous solution and parameter value. *solution = *previous_u; *continuation_parameter = old_continuation_parameter; // Compute new predictor with smaller ds apply_predictor(); } else { // Set step convergence and break out arcstep_converged=true; break; // out of arclength reduction loop } } // end loop over arclength reductions // Check for convergence of the whole arcstep. If not converged at this // point, we have no choice but to quit. if (!arcstep_converged) { libMesh::out << "Arcstep failed to converge after max number of reductions! Exiting..." << std::endl; libmesh_error(); } // Print converged solution control parameter and max value. libMesh::out << "lambda_current=" << *continuation_parameter << std::endl; //libMesh::out << "u_max=" << solution->max() << std::endl; // Reset old stream precision and flags. libMesh::out.precision(old_precision); libMesh::out.unsetf(std::ios_base::scientific); // Note: we don't want to go on to the next guess yet, since the user may // want to post-process this data. It's up to the user to call advance_arcstep() // when they are ready to go on. }
void RBConstructionBase<Base>::initialize_training_parameters(const RBParameters& mu_min, const RBParameters& mu_max, unsigned int n_training_samples, std::map<std::string,bool> log_param_scale, bool deterministic) { // Print out some info about the training set initialization libMesh::out << "Initializing training parameters with " << (deterministic ? "deterministic " : "random " ) << "training set..." << std::endl; { std::map<std::string,bool>::iterator it = log_param_scale.begin(); std::map<std::string,bool>::const_iterator it_end = log_param_scale.end(); for(; it != it_end; ++it) { libMesh::out << "Parameter " << it->first << ": log scaling = " << it->second << std::endl; } } libMesh::out << std::endl; if(deterministic) { generate_training_parameters_deterministic(this->comm(), log_param_scale, training_parameters, n_training_samples, mu_min, mu_max, serial_training_set); } else { // Generate random training samples for all parameters generate_training_parameters_random(this->comm(), log_param_scale, training_parameters, n_training_samples, mu_min, mu_max, this->training_parameters_random_seed, serial_training_set); } // For each parameter that only allows discrete values, we "snap" to the nearest // allowable discrete value if(get_n_discrete_params() > 0) { std::map< std::string, NumericVector<Number>* >::iterator it = training_parameters.begin(); std::map< std::string, NumericVector<Number>* >::const_iterator it_end = training_parameters.end(); for( ; it != it_end; ++it) { std::string param_name = it->first; if(is_discrete_parameter(param_name)) { std::vector<Real> discrete_values = get_discrete_parameter_values().find(param_name)->second; NumericVector<Number>* training_vector = it->second; for(numeric_index_type index=training_vector->first_local_index(); index<training_vector->last_local_index(); index++) { Real value = libmesh_real((*training_vector)(index)); Real nearest_discrete_value = get_closest_value(value, discrete_values); training_vector->set(index, nearest_discrete_value); } } } } training_parameters_initialized = true; }
void AdjointRefinementEstimator::estimate_error (const System& _system, ErrorVector& error_per_cell, const NumericVector<Number>* solution_vector, bool /*estimate_parent_error*/) { // We have to break the rules here, because we can't refine a const System System& system = const_cast<System&>(_system); // An EquationSystems reference will be convenient. EquationSystems& es = system.get_equation_systems(); // The current mesh MeshBase& mesh = es.get_mesh(); // Resize the error_per_cell vector to be // the number of elements, initialized to 0. error_per_cell.clear(); error_per_cell.resize (mesh.max_elem_id(), 0.); // We'll want to back up all coarse grid vectors std::map<std::string, NumericVector<Number> *> coarse_vectors; for (System::vectors_iterator vec = system.vectors_begin(); vec != system.vectors_end(); ++vec) { // The (string) name of this vector const std::string& var_name = vec->first; coarse_vectors[var_name] = vec->second->clone().release(); } // Back up the coarse solution and coarse local solution NumericVector<Number> * coarse_solution = system.solution->clone().release(); NumericVector<Number> * coarse_local_solution = system.current_local_solution->clone().release(); // And make copies of the projected solution NumericVector<Number> * projected_solution; // And we'll need to temporarily change solution projection settings bool old_projection_setting; old_projection_setting = system.project_solution_on_reinit(); // Make sure the solution is projected when we refine the mesh system.project_solution_on_reinit() = true; // And it'll be best to avoid any repartitioning AutoPtr<Partitioner> old_partitioner = mesh.partitioner(); mesh.partitioner().reset(NULL); // And we can't allow any renumbering const bool old_renumbering_setting = mesh.allow_renumbering(); mesh.allow_renumbering(false); // Use a non-standard solution vector if necessary if (solution_vector && solution_vector != system.solution.get()) { NumericVector<Number> *newsol = const_cast<NumericVector<Number>*> (solution_vector); newsol->swap(*system.solution); system.update(); } #ifndef NDEBUG // n_coarse_elem is only used in an assertion later so // avoid declaring it unless asserts are active. const dof_id_type n_coarse_elem = mesh.n_elem(); #endif // Uniformly refine the mesh MeshRefinement mesh_refinement(mesh); libmesh_assert (number_h_refinements > 0 || number_p_refinements > 0); // FIXME: this may break if there is more than one System // on this mesh but estimate_error was still called instead of // estimate_errors for (unsigned int i = 0; i != number_h_refinements; ++i) { mesh_refinement.uniformly_refine(1); es.reinit(); } for (unsigned int i = 0; i != number_p_refinements; ++i) { mesh_refinement.uniformly_p_refine(1); es.reinit(); } // Copy the projected coarse grid solutions, which will be // overwritten by solve() projected_solution = NumericVector<Number>::build(mesh.comm()).release(); projected_solution->init(system.solution->size(), true, SERIAL); system.solution->localize(*projected_solution, system.get_dof_map().get_send_list()); // Rebuild the rhs with the projected primal solution (dynamic_cast<ImplicitSystem&>(system)).assembly(true, false); NumericVector<Number> & projected_residual = (dynamic_cast<ExplicitSystem&>(system)).get_vector("RHS Vector"); projected_residual.close(); // Solve the adjoint problem on the refined FE space system.adjoint_solve(); // Now that we have the refined adjoint solution and the projected primal solution, // we first compute the global QoI error estimate // Resize the computed_global_QoI_errors vector to hold the error estimates for each QoI computed_global_QoI_errors.resize(system.qoi.size()); // Loop over all the adjoint solutions and get the QoI error // contributions from all of them for (unsigned int j=0; j != system.qoi.size(); j++) { computed_global_QoI_errors[j] = projected_residual.dot(system.get_adjoint_solution(j)); } // Done with the global error estimates, now construct the element wise error indicators // We ought to account for 'spill-over' effects while computing the // element error indicators This happens because the same dof is // shared by multiple elements, one way of mitigating this is to // scale the contribution from each dof by the number of elements it // belongs to We first obtain the number of elements each node // belongs to // A map that relates a node id to an int that will tell us how many elements it is a node of LIBMESH_BEST_UNORDERED_MAP<dof_id_type, unsigned int>shared_element_count; // To fill this map, we will loop over elements, and then in each element, we will loop // over the nodes each element contains, and then query it for the number of coarse // grid elements it was a node of // We will be iterating over all the active elements in the fine mesh that live on // this processor MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); // Keep track of which nodes we have already dealt with LIBMESH_BEST_UNORDERED_SET<dof_id_type> processed_node_ids; // Start loop over elems for(; elem_it != elem_end; ++elem_it) { // Pointer to this element const Elem* elem = *elem_it; // Loop over the nodes in the element for(unsigned int n=0; n != elem->n_nodes(); ++n) { // Get a pointer to the current node Node* node = elem->get_node(n); // Get the id of this node dof_id_type node_id = node->id(); // If we havent already processed this node, do so now if(processed_node_ids.find(node_id) == processed_node_ids.end()) { // Declare a neighbor_set to be filled by the find_point_neighbors std::set<const Elem *> fine_grid_neighbor_set; // Call find_point_neighbors to fill the neighbor_set elem->find_point_neighbors(*node, fine_grid_neighbor_set); // A vector to hold the coarse grid parents neighbors std::vector<dof_id_type> coarse_grid_neighbors; // Iterators over the fine grid neighbors set std::set<const Elem*>::iterator fine_neighbor_it = fine_grid_neighbor_set.begin(); const std::set<const Elem*>::iterator fine_neighbor_end = fine_grid_neighbor_set.end(); // Loop over all the fine neighbors of this node for(; fine_neighbor_it != fine_neighbor_end ; ++fine_neighbor_it) { // Pointer to the current fine neighbor element const Elem* fine_elem = *fine_neighbor_it; // Find the element id for the corresponding coarse grid element const Elem* coarse_elem = fine_elem; for (unsigned int j = 0; j != number_h_refinements; ++j) { libmesh_assert (coarse_elem->parent()); coarse_elem = coarse_elem->parent(); } // Loop over the existing coarse neighbors and check if this one is // already in there const dof_id_type coarse_id = coarse_elem->id(); std::size_t j = 0; for (; j != coarse_grid_neighbors.size(); j++) { // If the set already contains this element break out of the loop if(coarse_grid_neighbors[j] == coarse_id) { break; } } // If we didn't leave the loop even at the last element, // this is a new neighbour, put in the coarse_grid_neighbor_set if(j == coarse_grid_neighbors.size()) { coarse_grid_neighbors.push_back(coarse_id); } } // End loop over fine neighbors // Set the shared_neighbour index for this node to the // size of the coarse grid neighbor set shared_element_count[node_id] = libmesh_cast_int<unsigned int>(coarse_grid_neighbors.size()); // Add this node to processed_node_ids vector processed_node_ids.insert(node_id); } // End if not processed node } // End loop over nodes } // End loop over elems // Get a DoF map, will be used to get the nodal dof_indices for each element DofMap &dof_map = system.get_dof_map(); // The global DOF indices, we will use these later on when we compute the element wise indicators std::vector<dof_id_type> dof_indices; // Localize the global rhs and adjoint solution vectors (which might be shared on multiple processsors) onto a // local ghosted vector, this ensures each processor has all the dof_indices to compute an error indicator for // an element it owns AutoPtr<NumericVector<Number> > localized_projected_residual = NumericVector<Number>::build(system.comm()); localized_projected_residual->init(system.n_dofs(), system.n_local_dofs(), system.get_dof_map().get_send_list(), false, GHOSTED); projected_residual.localize(*localized_projected_residual, system.get_dof_map().get_send_list()); // Each adjoint solution will also require ghosting; for efficiency we'll reuse the same memory AutoPtr<NumericVector<Number> > localized_adjoint_solution = NumericVector<Number>::build(system.comm()); localized_adjoint_solution->init(system.n_dofs(), system.n_local_dofs(), system.get_dof_map().get_send_list(), false, GHOSTED); // We will loop over each adjoint solution, localize that adjoint // solution and then loop over local elements for (unsigned int i=0; i != system.qoi.size(); i++) { // Skip this QoI if not in the QoI Set if (_qoi_set.has_index(i)) { // Get the weight for the current QoI Real error_weight = _qoi_set.weight(i); (system.get_adjoint_solution(i)).localize(*localized_adjoint_solution, system.get_dof_map().get_send_list()); // Loop over elements MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for(; elem_it != elem_end; ++elem_it) { // Pointer to the element const Elem* elem = *elem_it; // Go up number_h_refinements levels up to find the coarse parent const Elem* coarse = elem; for (unsigned int j = 0; j != number_h_refinements; ++j) { libmesh_assert (coarse->parent()); coarse = coarse->parent(); } const dof_id_type e_id = coarse->id(); // Get the local to global degree of freedom maps for this element dof_map.dof_indices (elem, dof_indices); // We will have to manually do the dot products. Number local_contribution = 0.; for (unsigned int j=0; j != dof_indices.size(); j++) { // The contribution to the error indicator for this element from the current QoI local_contribution += (*localized_projected_residual)(dof_indices[j]) * (*localized_adjoint_solution)(dof_indices[j]); } // Multiply by the error weight for this QoI local_contribution *= error_weight; // FIXME: we're throwing away information in the // --enable-complex case error_per_cell[e_id] += static_cast<ErrorVectorReal> (libmesh_real(local_contribution)); } // End loop over elements } // End if belong to QoI set } // End loop over QoIs // Don't bother projecting the solution; we'll restore from backup // after coarsening system.project_solution_on_reinit() = false; // Uniformly coarsen the mesh, without projecting the solution libmesh_assert (number_h_refinements > 0 || number_p_refinements > 0); for (unsigned int i = 0; i != number_h_refinements; ++i) { mesh_refinement.uniformly_coarsen(1); // FIXME - should the reinits here be necessary? - RHS es.reinit(); } for (unsigned int i = 0; i != number_p_refinements; ++i) { mesh_refinement.uniformly_p_coarsen(1); es.reinit(); } // We should be back where we started libmesh_assert_equal_to (n_coarse_elem, mesh.n_elem()); // Restore old solutions and clean up the heap system.project_solution_on_reinit() = old_projection_setting; // Restore the coarse solution vectors and delete their copies *system.solution = *coarse_solution; delete coarse_solution; *system.current_local_solution = *coarse_local_solution; delete coarse_local_solution; delete projected_solution; for (System::vectors_iterator vec = system.vectors_begin(); vec != system.vectors_end(); ++vec) { // The (string) name of this vector const std::string& var_name = vec->first; // If it's a vector we already had (and not a newly created // vector like an adjoint rhs), we need to restore it. std::map<std::string, NumericVector<Number> *>::iterator it = coarse_vectors.find(var_name); if (it != coarse_vectors.end()) { NumericVector<Number> *coarsevec = it->second; system.get_vector(var_name) = *coarsevec; coarsevec->clear(); delete coarsevec; } } // Restore old partitioner and renumbering settings mesh.partitioner() = old_partitioner; mesh.allow_renumbering(old_renumbering_setting); // Fiinally sum the vector of estimated error values. this->reduce_error(error_per_cell, system.comm()); // We don't take a square root here; this is a goal-oriented // estimate not a Hilbert norm estimate. } // end estimate_error function
void EnsightIO::write_vector_ascii(const std::string &sys, const std::vector<std::string> &vec, const std::string &var_name) { std::ostringstream vec_file; vec_file<<_ensight_file_name<<"_"<<var_name<<".vec"; vec_file << std::setw(3) << std::setprecision(0) << std::setfill('0') << std::right << _time_steps.size()-1; FILE * fout = fopen(vec_file.str().c_str(),"w"); fprintf(fout,"Per vector per value\n"); fprintf(fout,"part\n"); fprintf(fout,"%10d\n",1); fprintf(fout,"coordinates\n"); // Get a constant reference to the mesh object. const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh(); // The dimension that we are running const unsigned int dim = the_mesh.mesh_dimension(); const System &system = _equation_systems.get_system(sys); const DofMap& dof_map = system.get_dof_map(); const unsigned int u_var = system.variable_number(vec[0]); const unsigned int v_var = system.variable_number(vec[1]); const unsigned int w_var = (dim==3) ? system.variable_number(vec[2]) : 0; std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_u; std::vector<dof_id_type> dof_indices_v; std::vector<dof_id_type> dof_indices_w; // Now we will loop over all the elements in the mesh. MeshBase::const_element_iterator el = the_mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = the_mesh.active_local_elements_end(); typedef std::map<int,std::vector<Real> > map_local_soln; typedef map_local_soln::iterator local_soln_iterator; map_local_soln local_soln; for ( ; el != end_el ; ++el){ const Elem* elem = *el; const FEType& fe_type = system.variable_type(u_var); dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u,u_var); dof_map.dof_indices (elem, dof_indices_v,v_var); if(dim==3) dof_map.dof_indices (elem, dof_indices,w_var); std::vector<Number> elem_soln_u; std::vector<Number> elem_soln_v; std::vector<Number> elem_soln_w; std::vector<Number> nodal_soln_u; std::vector<Number> nodal_soln_v; std::vector<Number> nodal_soln_w; elem_soln_u.resize(dof_indices_u.size()); elem_soln_v.resize(dof_indices_v.size()); if(dim == 3) elem_soln_w.resize(dof_indices_w.size()); for (unsigned int i = 0; i < dof_indices_u.size(); i++) { elem_soln_u[i] = system.current_solution(dof_indices_u[i]); elem_soln_v[i] = system.current_solution(dof_indices_v[i]); if(dim==3) elem_soln_w[i] = system.current_solution(dof_indices_w[i]); } FEInterface::nodal_soln (dim,fe_type,elem,elem_soln_u,nodal_soln_u); FEInterface::nodal_soln (dim,fe_type,elem,elem_soln_v,nodal_soln_v); if(dim == 3) FEInterface::nodal_soln (dim,fe_type,elem,elem_soln_w,nodal_soln_w); libmesh_assert_equal_to (nodal_soln_u.size(), elem->n_nodes()); libmesh_assert_equal_to (nodal_soln_v.size(), elem->n_nodes()); #ifdef LIBMESH_ENABLE_COMPLEX libMesh::err << "Complex-valued Ensight output not yet supported" << std::endl; libmesh_not_implemented() #endif for (unsigned int n=0; n<elem->n_nodes(); n++) { std::vector<Real> node_vec(3); node_vec[0]= libmesh_real(nodal_soln_u[n]); node_vec[1]= libmesh_real(nodal_soln_v[n]); node_vec[2]=0.0; if(dim==3) node_vec[2]= libmesh_real(nodal_soln_w[n]); local_soln[elem->node(n)] = node_vec; } } local_soln_iterator sol = local_soln.begin(); const local_soln_iterator sol_end = local_soln.end(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second[0])); sol = local_soln.begin(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second[1])); sol = local_soln.begin(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second[2])); fclose(fout); }
void EnsightIO::write_scalar_ascii(const std::string &sys, const std::string &var_name) { std::ostringstream scl_file; scl_file << _ensight_file_name << "_" << var_name << ".scl"; scl_file << std::setw(3) << std::setprecision(0) << std::setfill('0') << std::right << _time_steps.size()-1; FILE * fout = fopen(scl_file.str().c_str(),"w"); fprintf(fout,"Per node scalar value\n"); fprintf(fout,"part\n"); fprintf(fout,"%10d\n",1); fprintf(fout,"coordinates\n"); const MeshBase& the_mesh = MeshOutput<MeshBase>::mesh(); const unsigned int dim = the_mesh.mesh_dimension(); const System &system = _equation_systems.get_system(sys); const DofMap& dof_map = system.get_dof_map(); int var = system.variable_number(var_name); std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_scl; // Now we will loop over all the elements in the mesh. MeshBase::const_element_iterator el = the_mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = the_mesh.active_local_elements_end(); typedef std::map<int,Real> map_local_soln; typedef map_local_soln::iterator local_soln_iterator; map_local_soln local_soln; std::vector<Number> elem_soln; std::vector<Number> nodal_soln; for ( ; el != end_el ; ++el){ const Elem* elem = *el; const FEType& fe_type = system.variable_type(var); dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_scl, var); elem_soln.resize(dof_indices_scl.size()); for (unsigned int i = 0; i < dof_indices_scl.size(); i++) elem_soln[i] = system.current_solution(dof_indices_scl[i]); FEInterface::nodal_soln (dim,fe_type, elem, elem_soln, nodal_soln); libmesh_assert_equal_to (nodal_soln.size(), elem->n_nodes()); #ifdef LIBMESH_USE_COMPLEX_NUMBERS libMesh::err << "Complex-valued Ensight output not yet supported" << std::endl; libmesh_not_implemented(); #endif for (unsigned int n=0; n<elem->n_nodes(); n++) local_soln[elem->node(n)] = libmesh_real(nodal_soln[n]); } local_soln_iterator sol = local_soln.begin(); const local_soln_iterator sol_end = local_soln.end(); for(; sol != sol_end; ++sol) fprintf(fout,"%12.5e\n",static_cast<double>((*sol).second)); fclose(fout); }