Пример #1
0
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");
}
Пример #2
0
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;
}
Пример #3
0
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 ));
}
Пример #4
0
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
}
Пример #5
0
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;
}
Пример #6
0
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();
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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) );
}
Пример #10
0
// 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();
}
Пример #11
0
// 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.
}
Пример #12
0
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
Пример #14
0
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);

}
Пример #15
0
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);

}