Example #1
0
    Hermes::vector<Space<Scalar>*> CalculationContinuity<Scalar>::Record::load_spaces(Hermes::vector<Mesh*> meshes, Hermes::vector<Shapeset*> shapesets)
    {
			Hermes::vector<Space<Scalar>*> spaces;

      if(shapesets == Hermes::vector<Shapeset*>())
        for(unsigned int i = 0; i < meshes.size(); i++)
          shapesets.push_back(NULL);

      for(unsigned int i = 0; i < meshes.size(); i++)
      {
        std::stringstream filename;
        filename << CalculationContinuity<Scalar>::space_file_name << i << '_' << (std::string)"t = " << this->time << (std::string)"n = " << this->number << (std::string)".h2d";

        try
        {
          spaces.push_back(Space<Scalar>::load(filename.str().c_str(), meshes[i], false, NULL, shapesets[i]));
        }
        catch(Hermes::Exceptions::SpaceLoadFailureException& e)
        {
          throw IOCalculationContinuityException(CalculationContinuityException::spaces, IOCalculationContinuityException::input, filename.str().c_str(), e.what());
        }
        catch(std::exception& e)
        {
          throw IOCalculationContinuityException(CalculationContinuityException::spaces, IOCalculationContinuityException::input, filename.str().c_str(), e.what());
        }
      }
    }
Example #2
0
    Adapt<Scalar>::Adapt(Hermes::vector<Space<Scalar>*> spaces,
      Hermes::vector<ProjNormType> proj_norms) :
    spaces(spaces),
      num_act_elems(-1),
      have_errors(false),
      have_coarse_solutions(false),
      have_reference_solutions(false)
    {
      // sanity check
      if (proj_norms.size() > 0 && spaces.size() != proj_norms.size())
        error("Mismatched numbers of spaces and projection types in Adapt<Scalar>::Adapt().");

      this->num = spaces.size();

      // sanity checks
      error_if(this->num <= 0, "Too few components (%d), only %d supported.", this->num, H2D_MAX_COMPONENTS);
      error_if(this->num > H2D_MAX_COMPONENTS, "Too many components (%d), only %d supported.", this->num, H2D_MAX_COMPONENTS);

      // reset values
      memset(errors, 0, sizeof(errors));
      memset(sln, 0, sizeof(sln));
      memset(rsln, 0, sizeof(rsln));

      // if norms were not set by the user, set them to defaults
      // according to spaces
      if (proj_norms.size() == 0) 
      {
        for (int i = 0; i < this->num; i++) 
        {
          switch (spaces[i]->get_type()) 
          {
          case HERMES_H1_SPACE: proj_norms.push_back(HERMES_H1_NORM); break;
          case HERMES_HCURL_SPACE: proj_norms.push_back(HERMES_HCURL_NORM); break;
          case HERMES_HDIV_SPACE: proj_norms.push_back(HERMES_HDIV_NORM); break;
          case HERMES_L2_SPACE: proj_norms.push_back(HERMES_L2_NORM); break;
          default: error("Unknown space type in Adapt<Scalar>::Adapt().");
          }
        }
      }

      // assign norm weak forms  according to norms selection
      for (int i = 0; i < this->num; i++)
        for (int j = 0; j < this->num; j++)
        {
          error_form[i][j] = NULL;
          norm_form[i][j] = NULL;
        }

      for (int i = 0; i < this->num; i++)
      {
        error_form[i][i] = new MatrixFormVolError(proj_norms[i]);
        norm_form[i][i] = error_form[i][i];
      }
    }
MeshFunction<double>* FilterVectorPotential::clone()
{
  Hermes::vector<MeshFunction<double>*> fns;
  Hermes::vector<int> items;
  for(int i = 0; i < this->num; i++)
  {
    fns.push_back(this->sln[i]->clone());
    items.push_back(item[i]);
  }
  return new FilterVectorPotential(fns, items);
}
Example #4
0
// Set Dirichlet boundary values.
void ModuleBasic::set_dirichlet_values(const std::vector<int> &bdy_markers_dirichlet,
                                       const std::vector<double> &bdy_values_dirichlet)
{
  Hermes::vector<int> tm;
  for (unsigned int i = 0; i < bdy_markers_dirichlet.size(); i++) {
    tm.push_back(bdy_markers_dirichlet[i]);
  }
  Hermes::vector<double> tv;
  for (unsigned int i = 0; i < bdy_values_dirichlet.size(); i++) {
    tv.push_back(bdy_values_dirichlet[i]);
  }
  if (tm.size() != tv.size()) error("Mismatched numbers of Dirichlet boundary markers and values.");
  for (unsigned int i = 0; i < tm.size(); i++) this->bc_values.add_const(tm[i], tv[i]);
}
Example #5
0
void SimpleFilter::precalculate(int order, int mask)
{
  if (mask & (H2D_FN_DX | H2D_FN_DY | H2D_FN_DXX | H2D_FN_DYY | H2D_FN_DXY))
    error("Filter not defined for derivatives.");

  Quad2D* quad = quads[cur_quad];
  int np = quad->get_num_points(order);
  Node* node = new_node(H2D_FN_VAL, np);

  // precalculate all solutions
  for (int i = 0; i < num; i++)
    sln[i]->set_quad_order(order, item[i]);

  for (int j = 0; j < num_components; j++)
  {
    // obtain corresponding tables
    scalar* tab[10];
    for (int i = 0; i < num; i++)
    {
      int a = 0, b = 0, mask = item[i];
      if (mask >= 0x40) { a = 1; mask >>= 6; }
      while (!(mask & 1)) { mask >>= 1; b++; }
      tab[i] = sln[i]->get_values(num_components == 1 ? a : j, b);
      if (tab[i] == NULL) error("Value of 'item%d' is incorrect in filter definition.", i+1);
    }

		Hermes::vector<scalar*> values;
		for(int i = 0; i < this->num; i++)
			values.push_back(tab[i]);

    // apply the filter
		filter_fn(np, values, node->values[j][0]);
  }
MeshFunction<double>* FilterFluxDensity::clone()
{
  Hermes::vector<MeshFunction<double>*> fns;
  for(int i = 0; i < this->num; i++)
    fns.push_back(this->sln[i]->clone());
  return new FilterFluxDensity(fns);
}
Example #7
0
    void SimpleFilter<Scalar>::precalculate(int order, int mask)
    {
      if(mask & (H2D_FN_DX | H2D_FN_DY | H2D_FN_DXX | H2D_FN_DYY | H2D_FN_DXY))
        throw Hermes::Exceptions::Exception("Filter not defined for derivatives.");

      Quad2D* quad = this->quads[this->cur_quad];
      int np = quad->get_num_points(order, this->element->get_mode());
      struct Function<Scalar>::Node* node = this->new_node(H2D_FN_VAL, np);

      // precalculate all solutions
      for (int i = 0; i < this->num; i++)
        this->sln[i]->set_quad_order(order, item[i]);

      for (int j = 0; j < this->num_components; j++)
      {
        // obtain corresponding tables
        Scalar* tab[H2D_MAX_COMPONENTS];
        for (int i = 0; i < this->num; i++)
        {
          int a = 0, b = 0, mask = item[i];
          if(mask >= 0x40) { a = 1; mask >>= 6; }
          while (!(mask & 1)) { mask >>= 1; b++; }
          tab[i] = this->sln[i]->get_values(this->num_components == 1 ? a : j, b);
          if(tab[i] == nullptr) throw Hermes::Exceptions::Exception("Value of 'item%d' is incorrect in filter definition.", i + 1);
        }

        Hermes::vector<Scalar*> values;
        for(int i = 0; i < this->num; i++)
          values.push_back(tab[i]);

        // apply the filter
        filter_fn(np, values, node->values[j][0]);
      }
    void Continuity<Scalar>::Record::load_spaces(Hermes::vector<Space<Scalar>*> spaces, Hermes::vector<SpaceType> space_types, Hermes::vector<Mesh*> meshes, Hermes::vector<Shapeset*> shapesets)
    {
      if(shapesets == Hermes::vector<Shapeset*>())
        for(unsigned int i = 0; i < spaces.size(); i++)
          shapesets.push_back(NULL);

      for(unsigned int i = 0; i < spaces.size(); i++)
      {
        std::stringstream filename;
        filename << Continuity<Scalar>::spaceFileName << i << '_' << (std::string)"t = " << this->time << (std::string)"n = " << this->number << (std::string)".h2d";

        spaces[i]->free();

        switch(space_types[i])
        {
        case HERMES_H1_SPACE:
          dynamic_cast<H1Space<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
          break;
        case HERMES_HCURL_SPACE:
          dynamic_cast<HcurlSpace<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
          break;
        case HERMES_HDIV_SPACE:
          dynamic_cast<HdivSpace<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
          break;
        case HERMES_L2_SPACE:
          dynamic_cast<L2Space<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
          break;
        }
      }
    }
Example #9
0
// Set material markers, and check compatibility with mesh file.
void ModuleBasic::set_material_markers(const std::vector<int> &m_markers)
{
  this->mat_markers = m_markers;
  // FIXME: these global arrays need to be removed.
  for (unsigned int i = 0; i < m_markers.size(); i++) {
    _global_mat_markers.push_back(m_markers[i]);;
  }
}
Example #10
0
// Set Dirichlet boundary markers.
void ModuleBasic::set_dirichlet_markers(const std::vector<int> &bdy_markers_dirichlet)
{
  //this->bdy_markers_dirichlet = bdy_markers_dirichlet;
  Hermes::vector<int> t;
  for (unsigned int i = 0; i < bdy_markers_dirichlet.size(); i++) {
    t.push_back(bdy_markers_dirichlet[i]);
  }
  this->bc_types.add_bc_dirichlet(t);
}
Example #11
0
// Set Newton boundary markers.
void ModuleBasic::set_newton_markers(const std::vector<int> &bdy_markers_newton)
{
  this->bdy_markers_newton = bdy_markers_newton;
  Hermes::vector<int> t;
  for (unsigned int i = 0; i < bdy_markers_newton.size(); i++) {
    t.push_back(bdy_markers_newton[i]);
  }
  this->bc_types.add_bc_newton(t);
}
Example #12
0
    void WeakForm<Scalar>::cloneMembers(const WeakForm<Scalar>* otherWf)
    {
      this->mfvol.clear();
      this->mfsurf.clear();
      this->mfDG.clear();
      this->vfvol.clear();
      this->vfsurf.clear();
      this->vfDG.clear();
      this->forms.clear();
      this->ext.clear();

      for(unsigned int i = 0; i < otherWf->forms.size(); i++)
      {
        if(dynamic_cast<MatrixFormVol<Scalar>*>(otherWf->forms[i]) != NULL)
          this->forms.push_back((dynamic_cast<MatrixFormVol<Scalar>*>(otherWf->forms[i]))->clone());
        if(dynamic_cast<MatrixFormSurf<Scalar>*>(otherWf->forms[i]) != NULL)
          this->forms.push_back((dynamic_cast<MatrixFormSurf<Scalar>*>(otherWf->forms[i]))->clone());
        if(dynamic_cast<MatrixFormDG<Scalar>*>(otherWf->forms[i]) != NULL)
          this->forms.push_back((dynamic_cast<MatrixFormDG<Scalar>*>(otherWf->forms[i]))->clone());

        if(dynamic_cast<VectorFormVol<Scalar>*>(otherWf->forms[i]) != NULL)
          this->forms.push_back((dynamic_cast<VectorFormVol<Scalar>*>(otherWf->forms[i]))->clone());
        if(dynamic_cast<VectorFormSurf<Scalar>*>(otherWf->forms[i]) != NULL)
          this->forms.push_back((dynamic_cast<VectorFormSurf<Scalar>*>(otherWf->forms[i]))->clone());
        if(dynamic_cast<VectorFormDG<Scalar>*>(otherWf->forms[i]) != NULL)
          this->forms.push_back((dynamic_cast<VectorFormDG<Scalar>*>(otherWf->forms[i]))->clone());

        Hermes::vector<MeshFunction<Scalar>*> newExt;
        for(unsigned int ext_i = 0; ext_i < otherWf->forms[i]->ext.size(); ext_i++)
          newExt.push_back(otherWf->forms[i]->ext[ext_i]->clone());
        this->forms.back()->set_ext(newExt);
        this->forms.back()->wf = this;

        if(dynamic_cast<MatrixFormVol<Scalar>*>(otherWf->forms[i]) != NULL)
          this->mfvol.push_back(dynamic_cast<MatrixFormVol<Scalar>*>(this->forms.back()));
        if(dynamic_cast<MatrixFormSurf<Scalar>*>(otherWf->forms[i]) != NULL)
          this->mfsurf.push_back(dynamic_cast<MatrixFormSurf<Scalar>*>(this->forms.back()));
        if(dynamic_cast<MatrixFormDG<Scalar>*>(otherWf->forms[i]) != NULL)
          this->mfDG.push_back(dynamic_cast<MatrixFormDG<Scalar>*>(this->forms.back()));

        if(dynamic_cast<VectorFormVol<Scalar>*>(otherWf->forms[i]) != NULL)
          this->vfvol.push_back(dynamic_cast<VectorFormVol<Scalar>*>(this->forms.back()));
        if(dynamic_cast<VectorFormSurf<Scalar>*>(otherWf->forms[i]) != NULL)
          this->vfsurf.push_back(dynamic_cast<VectorFormSurf<Scalar>*>(this->forms.back()));
        if(dynamic_cast<VectorFormDG<Scalar>*>(otherWf->forms[i]) != NULL)
          this->vfDG.push_back(dynamic_cast<VectorFormDG<Scalar>*>(this->forms.back()));
      }
      for(unsigned int i = 0; i < otherWf->ext.size(); i++)
      {
        this->ext.push_back(otherWf->ext[i]->clone());
        if(dynamic_cast<Solution<Scalar>*>(otherWf->ext[i]) != NULL)
        {
          dynamic_cast<Solution<Scalar>*>(this->ext.back())->set_type(dynamic_cast<Solution<Scalar>*>(otherWf->ext[i])->get_type());
        }
      }
    }
Example #13
0
// Calculate norm of a (possibly vector-valued) solution.
// Take norm from spaces where these solutions belong.
double calc_norms(Hermes::vector<Solution*> slns)
{
  // Calculate norms for all solutions.
  Hermes::vector<double> norms;
  int n = slns.size();
  for (int i=0; i<n; i++) {
    switch (slns[i]->get_space_type()) {
      case HERMES_H1_SPACE: norms.push_back(calc_norm(slns[i], HERMES_H1_NORM)); break;
      case HERMES_HCURL_SPACE: norms.push_back(calc_norm(slns[i], HERMES_HCURL_NORM)); break;
      case HERMES_HDIV_SPACE: norms.push_back(calc_norm(slns[i], HERMES_HDIV_NORM)); break;
      case HERMES_L2_SPACE: norms.push_back(calc_norm(slns[i], HERMES_L2_NORM)); break;
      default: error("Internal in calc_norms(): unknown space type.");
    }
  }
  // Calculate the resulting norm.
  double result = 0;
  for (int i=0; i<n; i++) result += norms[i]*norms[i];
  return sqrt(result);
}
Example #14
0
  Hermes::vector<Cand> create_candidates(Element* e, int quad_order)
  {
    Hermes::vector<Cand> candidates;

    // Get the current order range.
    int current_min_order, current_max_order;
    this->get_current_order_range(e, current_min_order, current_max_order);

    int order_h = H2D_GET_H_ORDER(quad_order), order_v = H2D_GET_V_ORDER(quad_order);

    if(current_max_order < std::max(order_h, order_v))
      current_max_order = std::max(order_h, order_v);

    int last_order_h = std::min(current_max_order, order_h + 1), last_order_v = std::min(current_max_order, order_v + 1);
    int last_order = H2D_MAKE_QUAD_ORDER(last_order_h, last_order_v);

    switch(strategy)
    {
    case(hORpSelectionBasedOnDOFs):
      {
        candidates.push_back(Cand(H2D_REFINEMENT_P, quad_order));
      }
    case(hXORpSelectionBasedOnError):
      {
        candidates.push_back(Cand(H2D_REFINEMENT_P, last_order));
        candidates.push_back(Cand(H2D_REFINEMENT_H, quad_order, quad_order, quad_order, quad_order));
        return candidates;
      }
      break;
    case(isoHPSelectionBasedOnDOFs):
      {
        this->cand_list = H2D_HP_ISO;
        return H1ProjBasedSelector<complex>::create_candidates(e, quad_order);
      }
      break;
    case(anisoHPSelectionBasedOnDOFs):
      {
        this->cand_list = H2D_HP_ANISO;
        return H1ProjBasedSelector<complex>::create_candidates(e, quad_order);
      }
      break;
    }
  }
Example #15
0
      MeshFunctionSharedPtr<Scalar> Limiter<Scalar>::get_solution()
      {
        // A check.
        warn_if(this->component_count > 1, "One solution asked from a Limiter, but multiple solutions exist for limiting.");

        MeshFunctionSharedPtr<Scalar> solution(new Solution<Scalar>());
        Hermes::vector<MeshFunctionSharedPtr<Scalar> > solutions;
        solutions.push_back(solution);
        this->get_solutions(solutions);
        return solutions.back();
      }
Example #16
0
 void OGProjection<Scalar>::project_global(Space<Scalar>* space, MeshFunction<Scalar>* source_meshfn,
   Scalar* target_vec, Hermes::MatrixSolverType matrix_solver_type,
   ProjNormType proj_norm)
 {
   Hermes::vector<Space<Scalar>*> spaces;
   spaces.push_back(space);
   Hermes::vector<MeshFunction<Scalar>*> source_meshfns;
   source_meshfns.push_back(source_meshfn);
   Hermes::vector<ProjNormType> proj_norms;
   proj_norms.push_back(proj_norm);
   project_global(spaces, source_meshfns, target_vec, matrix_solver_type, proj_norms);
 }
Example #17
0
bool calc_errors(Hermes::vector<Solution* > left, Hermes::vector<Solution *> right, Hermes::vector<double> & err_abs, Hermes::vector<double> & norm_vals,
                 double & err_abs_total, double & norm_total, double & err_rel_total, Hermes::vector<ProjNormType> norms)
{
  bool default_norms = false;
  // Checks.
  if(left.size() != right.size())
    return false;
  if (norms != Hermes::vector<ProjNormType>())
  {
    if(left.size() != norms.size())
      return false;
  }
  else
    default_norms = true;

  // Zero the resulting Tuples.
  err_abs.clear();
  norm_vals.clear();

  // Zero the sums.
  err_abs_total = 0;
  norm_total = 0;
  err_rel_total = 0;

  // Calculation.
  for(unsigned int i = 0; i < left.size(); i++)
  {
    err_abs.push_back(calc_abs_error(left[i], right[i], default_norms ? HERMES_H1_NORM : norms[i]));
    norm_vals.push_back(calc_norm(right[i], default_norms ? HERMES_H1_NORM : norms[i]));
    err_abs_total += err_abs[i] * err_abs[i];
    norm_total += norm_vals[i] * norm_vals[i];
  }

  err_abs_total = sqrt(err_abs_total);
  norm_total = sqrt(norm_total);
  err_rel_total = err_abs_total / norm_total * 100.;

  // Everything went well, return appropriate flag.
  return true;
}
Example #18
0
    Hermes::vector<unsigned int> NeighborSearch<Scalar>::get_transforms(uint64_t sub_idx) const
    {
      Hermes::vector<unsigned int> transformations_backwards;
      while (sub_idx > 0)
      {
        transformations_backwards.push_back((sub_idx - 1) & 7);
        sub_idx = (sub_idx - 1) >> 3;
      }
      Hermes::vector<unsigned int> transformations;
      for(unsigned int i = 0; i < transformations_backwards.size(); i++)
        transformations.push_back(transformations_backwards[transformations_backwards.size() - 1 - i]);

      return transformations;
    }
Example #19
0
    void OGProjection<Scalar>::project_global(Space<Scalar>* space,
      Solution<Scalar>* sol_src, Solution<Scalar>* sol_dest,
      Hermes::MatrixSolverType matrix_solver_type,
      ProjNormType proj_norm)
    {
      Hermes::vector<Space<Scalar>*> spaces;
      spaces.push_back(space);
      Hermes::vector<Solution<Scalar>*> sols_src;
      sols_src.push_back(sol_src);
      Hermes::vector<Solution<Scalar>*> sols_dest;
      sols_dest.push_back(sol_dest);
      Hermes::vector<ProjNormType> proj_norms;
      if(proj_norm != HERMES_UNSET_NORM)
        proj_norms.push_back(proj_norm);

      project_global(spaces, sols_src, sols_dest, matrix_solver_type, proj_norms);
    }
    void CalculationContinuity<Scalar>::Record::load_spaces(Hermes::vector<Space<Scalar>*> spaces, Hermes::vector<SpaceType> space_types, Hermes::vector<Mesh*> meshes, Hermes::vector<Shapeset*> shapesets)
    {
      if(shapesets == Hermes::vector<Shapeset*>())
        for(unsigned int i = 0; i < spaces.size(); i++)
          shapesets.push_back(NULL);

      for(unsigned int i = 0; i < spaces.size(); i++)
      {
        std::stringstream filename;
        filename << CalculationContinuity<Scalar>::spaceFileName << i << '_' << (std::string)"t = " << this->time << (std::string)"n = " << this->number << (std::string)".h2d";

        spaces[i]->free();

        try
        {
          switch(space_types[i])
          {
          case HERMES_H1_SPACE:
            dynamic_cast<H1Space<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
            break;
          case HERMES_HCURL_SPACE:
            dynamic_cast<HcurlSpace<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
            break;
          case HERMES_HDIV_SPACE:
            dynamic_cast<HdivSpace<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
            break;
          case HERMES_L2_SPACE:
            dynamic_cast<L2Space<Scalar>*>(spaces[i])->load(filename.str().c_str(), meshes[i], shapesets[i]);
            break;
          }
        }
        catch(Hermes::Exceptions::SpaceLoadFailureException& e)
        {
          throw IOCalculationContinuityException(CalculationContinuityException::spaces, IOCalculationContinuityException::input, filename.str().c_str(), e.what());
        }
        catch(std::exception& e)
        {
          throw IOCalculationContinuityException(CalculationContinuityException::spaces, IOCalculationContinuityException::input, filename.str().c_str(), e.what());
        }
      }
    }
Example #21
0
KellyTypeAdapt::KellyTypeAdapt(Hermes::vector< Space* > spaces_,
                               Hermes::vector< ProjNormType > norms_,
                               bool ignore_visited_segments_,
                               Hermes::vector<interface_estimator_scaling_fn_t> interface_scaling_fns_)
  : Adapt(spaces_, norms_)
{
  error_estimators_surf.reserve(num);
  error_estimators_vol.reserve(num);

  if (interface_scaling_fns_.size() == 0)
  {
    interface_scaling_fns_.reserve(num);
    for (int i = 0; i < num; i++)
      interface_scaling_fns_.push_back(scale_by_element_diameter);
  }
  use_aposteriori_interface_scaling = true;
  interface_scaling_fns = interface_scaling_fns_;
  interface_scaling_const = boundary_scaling_const = volumetric_scaling_const = 1.0;
  ignore_visited_segments = ignore_visited_segments_;

  element_markers_conversion = spaces_[0]->get_mesh()->element_markers_conversion;
  boundary_markers_conversion = spaces_[0]->get_mesh()->boundary_markers_conversion;
}
Example #22
0
int main(int argc, char* argv[])
{
  if (NUMBER_OF_EIGENVALUES > 6) error("Maximum number of eigenvalues is 6.");
  info("Desired number of eigenvalues: %d.", NUMBER_OF_EIGENVALUES);

  // Load the mesh.
  Mesh mesh;
  H2DReader mloader;
  mloader.load("domain.mesh", &mesh);

  // Perform initial mesh refinements (optional).
  for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements();

  // Enter boundary markers. 
  // Note: "essential" means that solution value is prescribed.
  BCTypes bc_types;
  bc_types.add_bc_dirichlet(Hermes::vector<int>(BDY_BOTTOM, BDY_RIGHT, BDY_TOP, BDY_LEFT));

  // Enter Dirichlet boudnary values.
  BCValues bc_values;
  bc_values.add_zero(Hermes::vector<int>(BDY_BOTTOM, BDY_RIGHT, BDY_TOP, BDY_LEFT));

  // Create an H1 space with default shapeset.
  H1Space space(&mesh, &bc_types, &bc_values, P_INIT);

  // Initialize the weak formulation for the left hand side i.e. H 
  WeakForm wf_left, wf_right;
  wf_left.add_matrix_form(callback(bilinear_form_left));
  wf_right.add_matrix_form(callback(bilinear_form_right));

  // Initialize refinement selector.
  H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);

  // Initialize views.
  ScalarView sview_1("", new WinGeom(0, 0, 350, 250));
  sview_1.show_mesh(false);
  sview_1.fix_scale_width(60);
  ScalarView sview_2("", new WinGeom(360, 0, 350, 250));
  sview_2.show_mesh(false);
  sview_2.fix_scale_width(60);
  ScalarView sview_3("", new WinGeom(720, 0, 350, 250));
  sview_3.show_mesh(false);
  sview_3.fix_scale_width(60);
  ScalarView sview_4("", new WinGeom(0, 305, 350, 250));
  sview_4.show_mesh(false);
  sview_4.fix_scale_width(60);
  ScalarView sview_5("", new WinGeom(360, 305, 350, 250));
  sview_5.show_mesh(false);
  sview_5.fix_scale_width(60);
  ScalarView sview_6("", new WinGeom(720, 305, 350, 250));
  sview_6.show_mesh(false);
  sview_6.fix_scale_width(60);
  OrderView  oview("Polynomial orders", new WinGeom(1080, 0, 410, 350));

  // DOF and CPU convergence graphs.
  SimpleGraph graph_dof_est, graph_cpu_est;

  // Time measurement.
  TimePeriod cpu_time;
  cpu_time.tick();

  Solution sln[NUMBER_OF_EIGENVALUES], ref_sln[NUMBER_OF_EIGENVALUES];

  // Adaptivity loop:
  int as = 1;
  bool done = false;
  do
  {
    info("---- Adaptivity step %d:", as);
    info("Solving on reference mesh.");

    // Construct globally refined reference mesh and setup reference space.
    Space* ref_space = construct_refined_space(&space);
    int ref_ndof = Space::get_num_dofs(ref_space);
    info("ref_ndof: %d.", ref_ndof);

    // Initialize matrices and matrix solver on referenc emesh.
    SparseMatrix* matrix_left = create_matrix(matrix_solver);
    SparseMatrix* matrix_right = create_matrix(matrix_solver);
    Solver* solver = create_linear_solver(matrix_solver, matrix_left);

    // Assemble the matrices on reference mesh.
    bool is_linear = true;
    DiscreteProblem* dp_left = new DiscreteProblem(&wf_left, ref_space, is_linear);
    dp_left->assemble(matrix_left);
    DiscreteProblem* dp_right = new DiscreteProblem(&wf_right, ref_space, is_linear);
    dp_right->assemble(matrix_right);

    // Time measurement.
    cpu_time.tick();

    // Write matrix_left in MatrixMarket format.
    write_matrix_mm("mat_left.mtx", matrix_left);

    // Write matrix_left in MatrixMarket format.
    write_matrix_mm("mat_right.mtx", matrix_right);

    // Time measurement.
    cpu_time.tick(HERMES_SKIP);

    // Calling Python eigensolver. Solution will be written to "eivecs.dat".
    info("Calling Pysparse...");
    char call_cmd[255];
    sprintf(call_cmd, "python solveGenEigenFromMtx.py mat_left.mtx mat_right.mtx %g %d %g %d", 
	    TARGET_VALUE, NUMBER_OF_EIGENVALUES, TOL, MAX_ITER);
    system(call_cmd);
    info("Pysparse finished.");

    // Initializing solution vector, solution and ScalarView.
    double* ref_coeff_vec = new double[ref_ndof];
    //Solution sln[NUMBER_OF_EIGENVALUES], ref_sln[NUMBER_OF_EIGENVALUES];
    //ScalarView view("Solution", new WinGeom(0, 0, 440, 350));

    // Reading solution vectors from file and visualizing.
    double eigenval[NUMBER_OF_EIGENVALUES];
    FILE *file = fopen("eivecs.dat", "r");
    char line [64];                  // Maximum line size.
    fgets(line, sizeof line, file);  // ref_ndof
    int n = atoi(line);            
    if (n != ref_ndof) error("Mismatched ndof in the eigensolver output file.");  
    fgets(line, sizeof line, file);  // Number of eigenvectors in the file.
    int neig = atoi(line);
    if (neig != NUMBER_OF_EIGENVALUES) error("Mismatched number of eigenvectors in the eigensolver output file.");  
    for (int ieig = 0; ieig < NUMBER_OF_EIGENVALUES; ieig++) {
      // Get next eigenvalue from the file
      fgets(line, sizeof line, file);  // eigenval
      eigenval[ieig] = atof(line);            
      // Get the corresponding eigenvector.
      for (int i = 0; i < ref_ndof; i++) {  
        fgets(line, sizeof line, file);
        ref_coeff_vec[i] = atof(line);
      }

      // Convert coefficient vector into a Solution.
      Solution::vector_to_solution(ref_coeff_vec, ref_space, &(ref_sln[ieig]));

      // Project the fine mesh solution onto the coarse mesh.
      info("Projecting reference solution %d on coarse mesh.", ieig);
      OGProjection::project_global(&space, &(ref_sln[ieig]), &(sln[ieig]), matrix_solver);
    }  
    fclose(file);
    delete [] ref_coeff_vec;

    // FIXME: Below, the adaptivity is done for the last eigenvector only,
    // this needs to be changed to take into account all eigenvectors.

    // View the coarse mesh solution and polynomial orders.
    
    char title[100];
    if (NUMBER_OF_EIGENVALUES > 0) {
      sprintf(title, "Solution 0, val = %g", eigenval[0]);
      sview_1.set_title(title);
      sview_1.show(&(sln[0]));
    }
    if (NUMBER_OF_EIGENVALUES > 1) {
      sprintf(title, "Solution 1, val = %g", eigenval[1]);
      sview_2.set_title(title);
      sview_2.show(&(sln[1]));
    }
    if (NUMBER_OF_EIGENVALUES > 2) {
      sprintf(title, "Solution 2, val = %g", eigenval[2]);
      sview_3.set_title(title);
      sview_3.show(&(sln[2]));
    }
    if (NUMBER_OF_EIGENVALUES > 3) {
      sprintf(title, "Solution 3, val = %g", eigenval[3]);
      sview_4.set_title(title);
      sview_4.show(&(sln[3]));
    }
    if (NUMBER_OF_EIGENVALUES > 4) {
      sprintf(title, "Solution 4, val = %g", eigenval[4]);
      sview_5.set_title(title);
      sview_5.show(&(sln[4]));
    }
    if (NUMBER_OF_EIGENVALUES > 5) {
      sprintf(title, "Solution 5, val = %g", eigenval[5]);
      sview_6.set_title(title);
      sview_6.show(&(sln[5]));
    }
    oview.show(&space);

    // Calculate element errors and total error estimate.
    info("Calculating error estimate.");
    Hermes::vector<Space *> spaces;
    for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++) spaces.push_back(&space);
    Adapt* adaptivity = new Adapt(spaces);
 
    Hermes::vector<Solution *> slns;
    if (NUMBER_OF_EIGENVALUES > 0) slns.push_back(&sln[0]);
    if (NUMBER_OF_EIGENVALUES > 1) slns.push_back(&sln[1]);
    if (NUMBER_OF_EIGENVALUES > 2) slns.push_back(&sln[2]);
    if (NUMBER_OF_EIGENVALUES > 3) slns.push_back(&sln[3]);
    if (NUMBER_OF_EIGENVALUES > 4) slns.push_back(&sln[4]);
    if (NUMBER_OF_EIGENVALUES > 5) slns.push_back(&sln[5]);
    
    Hermes::vector<Solution *> ref_slns;
    if (NUMBER_OF_EIGENVALUES > 0) ref_slns.push_back(&ref_sln[0]);
    if (NUMBER_OF_EIGENVALUES > 1) ref_slns.push_back(&ref_sln[1]);
    if (NUMBER_OF_EIGENVALUES > 2) ref_slns.push_back(&ref_sln[2]);
    if (NUMBER_OF_EIGENVALUES > 3) ref_slns.push_back(&ref_sln[3]);
    if (NUMBER_OF_EIGENVALUES > 4) ref_slns.push_back(&ref_sln[4]);
    if (NUMBER_OF_EIGENVALUES > 5) ref_slns.push_back(&ref_sln[5]);
    Hermes::vector<double> component_errors;
    double err_est_rel = adaptivity->calc_err_est(slns, ref_slns, &component_errors) * 100;

    // Report results.
    info("ndof_coarse: %d, ndof_fine: %d.", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space));
    if (NUMBER_OF_EIGENVALUES > 0) info("err_est_rel[0]: %g%%", component_errors[0] * 100);
    if (NUMBER_OF_EIGENVALUES > 1) info("err_est_rel[1]: %g%%", component_errors[1] * 100);
    if (NUMBER_OF_EIGENVALUES > 2) info("err_est_rel[2]: %g%%", component_errors[2] * 100);
    if (NUMBER_OF_EIGENVALUES > 3) info("err_est_rel[3]: %g%%", component_errors[3] * 100);
    if (NUMBER_OF_EIGENVALUES > 4) info("err_est_rel[4]: %g%%", component_errors[4] * 100);
    if (NUMBER_OF_EIGENVALUES > 5) info("err_est_rel[5]: %g%%", component_errors[5] * 100);
   
    // Time measurement.
    cpu_time.tick();

    // Add entry to DOF and CPU convergence graphs.
    graph_dof_est.add_values(Space::get_num_dofs(&space), err_est_rel);
    graph_dof_est.save("conv_dof_est.dat");
    graph_cpu_est.add_values(cpu_time.accumulated(), err_est_rel);
    graph_cpu_est.save("conv_cpu_est.dat");

    // If err_est too large, adapt the mesh.
    if (err_est_rel < ERR_STOP) done = true;
    else
    {
      info("Adapting coarse mesh.");
      Hermes::vector<RefinementSelectors::Selector *> selectors;
      for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++)
        selectors.push_back(&selector);
      done = adaptivity->adapt(selectors, THRESHOLD, STRATEGY, MESH_REGULARITY);

      // Increase the counter of performed adaptivity steps.
      if (done == false)  as++;
    }
    if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true;

    // Clean up.
    delete solver;
    delete matrix_left;
    delete matrix_right;
    delete adaptivity;
    if(done == false) delete ref_space->get_mesh();
    delete ref_space;
    delete dp_left;
    delete dp_right;
  }
  while (done == false);

  // Wait for all views to be closed.
  View::wait();
  return 0;
};
Example #23
0
int main(int argc, char* argv[])
{
  // Time measurement.
  Hermes::Mixins::TimeMeasurable cpu_time;
  cpu_time.tick();
  
  // Load physical data of the problem.
  MaterialPropertyMaps matprop(N_GROUPS);
  matprop.set_D(D);
  matprop.set_Sigma_r(Sr);
  matprop.set_Sigma_s(Ss);
  matprop.set_Sigma_a(Sa);
  matprop.set_Sigma_f(Sf);
  matprop.set_nu(nu);
  matprop.set_chi(chi);
  matprop.validate();
  
  std::cout << matprop;

  // Use multimesh, i.e. create one mesh for each energy group.
  Hermes::vector<Mesh *> meshes;
  for (unsigned int g = 0; g < matprop.get_G(); g++) 
    meshes.push_back(new Mesh());
  
  // Load the mesh for the 1st group.
  MeshReaderH2D mloader;
  mloader.load(mesh_file.c_str(), meshes[0]);
 
  for (unsigned int g = 1; g < matprop.get_G(); g++) 
  {
    // Obtain meshes for the 2nd to 4th group by cloning the mesh loaded for the 1st group.
    meshes[g]->copy(meshes[0]);
    // Initial uniform refinements.
    for (int i = 0; i < INIT_REF_NUM[g]; i++) 
      meshes[g]->refine_all_elements();
  }
  for (int i = 0; i < INIT_REF_NUM[0]; i++) 
    meshes[0]->refine_all_elements();
  
  // Create pointers to solutions on coarse and fine meshes and from the latest power iteration, respectively.
  Hermes::vector<Solution<double>*> coarse_solutions, fine_solutions;
  Hermes::vector<MeshFunction<double>*> power_iterates;

  // Initialize all the new solution variables.
  for (unsigned int g = 0; g < matprop.get_G(); g++) 
  {
    coarse_solutions.push_back(new Solution<double>());
    fine_solutions.push_back(new Solution<double>());
    power_iterates.push_back(new ConstantSolution<double>(meshes[g], 1.0));   
  }
  
  // Create the approximation spaces with the default shapeset.
  H1Space<double> space1(meshes[0], P_INIT[0]);
  H1Space<double> space2(meshes[1], P_INIT[1]);
  H1Space<double> space3(meshes[2], P_INIT[2]);
  H1Space<double> space4(meshes[3], P_INIT[3]);
  Hermes::vector<const Space<double>*> const_spaces(&space1, &space2, &space3, &space4);
  Hermes::vector<Space<double>*> spaces(&space1, &space2, &space3, &space4);

  // Initialize the weak formulation.
  CustomWeakForm wf(matprop, power_iterates, k_eff, bdy_vacuum);
    
  // Initialize the discrete algebraic representation of the problem and its solver.
  //
  // Create the matrix and right-hand side vector for the solver.
  SparseMatrix<double>* mat = create_matrix<double>();
  Vector<double>* rhs = create_vector<double>();
  // Instantiate the solver itself.
  LinearMatrixSolver<double>* solver = create_linear_solver<double>( mat, rhs);

  // Initialize views.
  /* for 1280x800 display */
  ScalarView view1("Neutron flux 1", new WinGeom(0, 0, 320, 400));
  ScalarView view2("Neutron flux 2", new WinGeom(330, 0, 320, 400));
  ScalarView view3("Neutron flux 3", new WinGeom(660, 0, 320, 400));
  ScalarView view4("Neutron flux 4", new WinGeom(990, 0, 320, 400));
  OrderView oview1("Mesh for group 1", new WinGeom(0, 450, 320, 500));
  OrderView oview2("Mesh for group 2", new WinGeom(330, 450, 320, 500));
  OrderView oview3("Mesh for group 3", new WinGeom(660, 450, 320, 500));
  OrderView oview4("Mesh for group 4", new WinGeom(990, 450, 320, 500));

  /* for adjacent 1280x800 and 1680x1050 displays
  ScalarView view1("Neutron flux 1", new WinGeom(0, 0, 640, 480));
  ScalarView view2("Neutron flux 2", new WinGeom(650, 0, 640, 480));
  ScalarView view3("Neutron flux 3", new WinGeom(1300, 0, 640, 480));
  ScalarView view4("Neutron flux 4", new WinGeom(1950, 0, 640, 480));
  OrderView oview1("Mesh for group 1", new WinGeom(1300, 500, 340, 500));
  OrderView oview2("Mesh for group 2", new WinGeom(1650, 500, 340, 500));
  OrderView oview3("Mesh for group 3", new WinGeom(2000, 500, 340, 500));
  OrderView oview4("Mesh for group 4", new WinGeom(2350, 500, 340, 500));
  */

  Hermes::vector<ScalarView *> sviews(&view1, &view2, &view3, &view4);
  Hermes::vector<OrderView *> oviews(&oview1, &oview2, &oview3, &oview4); 
  for (unsigned int g = 0; g < matprop.get_G(); g++) 
  { 
    sviews[g]->show_mesh(false);
    sviews[g]->set_3d_mode(true);
  }
  
  // DOF and CPU convergence graphs
  GnuplotGraph graph_dof("Error convergence", "NDOF", "log(error)");
  graph_dof.add_row("H1 err. est. [%]", "r", "-", "o");
  graph_dof.add_row("L2 err. est. [%]", "g", "-", "s");
  graph_dof.add_row("Keff err. est. [milli-%]", "b", "-", "d");
  graph_dof.set_log_y();
  graph_dof.show_legend();
  graph_dof.show_grid();

  GnuplotGraph graph_dof_evol("Evolution of NDOF", "Adaptation step", "NDOF");
  graph_dof_evol.add_row("group 1", "r", "-", "o");
  graph_dof_evol.add_row("group 2", "g", "-", "x");
  graph_dof_evol.add_row("group 3", "b", "-", "+");
  graph_dof_evol.add_row("group 4", "m", "-", "*");
  graph_dof_evol.set_log_y();
  graph_dof_evol.set_legend_pos("bottom right");
  graph_dof_evol.show_grid();

  GnuplotGraph graph_cpu("Error convergence", "CPU time [s]", "log(error)");
  graph_cpu.add_row("H1 err. est. [%]", "r", "-", "o");
  graph_cpu.add_row("L2 err. est. [%]", "g", "-", "s");
  graph_cpu.add_row("Keff err. est. [milli-%]", "b", "-", "d");
  graph_cpu.set_log_y();
  graph_cpu.show_legend();
  graph_cpu.show_grid();

  // Initialize the refinement selectors.
  H1ProjBasedSelector<double> selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);
  Hermes::vector<RefinementSelectors::Selector<double>*> selectors;
  for (unsigned int g = 0; g < matprop.get_G(); g++) 
    selectors.push_back(&selector);
  
  Hermes::vector<MatrixFormVol<double>*> projection_jacobian;
  Hermes::vector<VectorFormVol<double>*> projection_residual;
  for (unsigned int g = 0; g < matprop.get_G(); g++) 
  {
    projection_jacobian.push_back(new H1AxisymProjectionJacobian(g));
    projection_residual.push_back(new H1AxisymProjectionResidual(g, power_iterates[g]));
  }
  
  Hermes::vector<ProjNormType> proj_norms_h1, proj_norms_l2;
  for (unsigned int g = 0; g < matprop.get_G(); g++)
  {
    proj_norms_h1.push_back(HERMES_H1_NORM);
    proj_norms_l2.push_back(HERMES_L2_NORM);
  }
  
  // Initial power iteration to obtain a coarse estimate of the eigenvalue and the fission source.
  Hermes::Mixins::Loggable::Static::info("Coarse mesh power iteration, %d + %d + %d + %d = %d ndof:", report_num_dofs(spaces));
  power_iteration(matprop, const_spaces, &wf, power_iterates, core, TOL_PIT_CM, matrix_solver);
  
  // Adaptivity loop:
  int as = 1; bool done = false;
  do 
  {
    Hermes::Mixins::Loggable::Static::info("---- Adaptivity step %d:", as);
    
    // Construct globally refined meshes and setup reference spaces on them.
    Hermes::vector<const Space<double>*> ref_spaces_const;
    Hermes::vector<Mesh *> ref_meshes;
    for (unsigned int g = 0; g < matprop.get_G(); g++) 
    { 
      ref_meshes.push_back(new Mesh());
      Mesh *ref_mesh = ref_meshes.back();      
      ref_mesh->copy(spaces[g]->get_mesh());
      ref_mesh->refine_all_elements();
      
      int order_increase = 1;
      ref_spaces_const.push_back(spaces[g]->dup(ref_mesh, order_increase));
    }

#ifdef WITH_PETSC    
    // PETSc assembling is currently slow for larger matrices, so we switch to 
    // UMFPACK when matrices of order >8000 start to appear.
    if (Space<double>::get_num_dofs(ref_spaces_const) > 8000 && matrix_solver == SOLVER_PETSC)
    {
      // Delete the old solver.
      delete mat;
      delete rhs;
      delete solver;
      
      // Create a new one.
      matrix_solver = SOLVER_UMFPACK;
      mat = create_matrix<double>();
      rhs = create_vector<double>();
      solver = create_linear_solver<double>( mat, rhs);
    }
#endif    

    // Solve the fine mesh problem.
    Hermes::Mixins::Loggable::Static::info("Fine mesh power iteration, %d + %d + %d + %d = %d ndof:", report_num_dofs(ref_spaces_const));
    power_iteration(matprop, ref_spaces_const, &wf, power_iterates, core, TOL_PIT_RM, matrix_solver);
    
    // Store the results.
    for (unsigned int g = 0; g < matprop.get_G(); g++) 
      fine_solutions[g]->copy((static_cast<Solution<double>*>(power_iterates[g])));

    Hermes::Mixins::Loggable::Static::info("Projecting fine mesh solutions on coarse meshes.");
    // This is commented out as the appropriate method was deleted in the commit
    // "Cleaning global projections" (b282194946225014faa1de37f20112a5a5d7ab5a).
    //OGProjection<double> ogProjection; ogProjection.project_global(spaces, projection_jacobian, projection_residual, coarse_solutions);

    // Time measurement.
    cpu_time.tick();

    // View the coarse mesh solution and meshes.
    for (unsigned int g = 0; g < matprop.get_G(); g++) 
    { 
      sviews[g]->show(coarse_solutions[g]); 
      oviews[g]->show(spaces[g]);
    }

    // Skip visualization time.
    cpu_time.tick(Hermes::Mixins::TimeMeasurable::HERMES_SKIP);

    // Report the number of negative eigenfunction values.
    Hermes::Mixins::Loggable::Static::info("Num. of negative values: %d, %d, %d, %d",
         get_num_of_neg(coarse_solutions[0]), get_num_of_neg(coarse_solutions[1]),
         get_num_of_neg(coarse_solutions[2]), get_num_of_neg(coarse_solutions[3]));

    // Calculate element errors and total error estimate.
    Adapt<double> adapt_h1(spaces);
    Adapt<double> adapt_l2(spaces);    
    for (unsigned int g = 0; g < matprop.get_G(); g++)
    {
      adapt_h1.set_error_form(g, g, new ErrorForm(proj_norms_h1[g]));
      adapt_l2.set_error_form(g, g, new ErrorForm(proj_norms_l2[g]));
    }
    
    // Calculate element errors and error estimates in H1 and L2 norms. Use the H1 estimate to drive adaptivity.
    Hermes::Mixins::Loggable::Static::info("Calculating errors.");
    Hermes::vector<double> h1_group_errors, l2_group_errors;
    double h1_err_est = adapt_h1.calc_err_est(coarse_solutions, fine_solutions, &h1_group_errors) * 100;
    double l2_err_est = adapt_l2.calc_err_est(coarse_solutions, fine_solutions, &l2_group_errors, false) * 100;

    // Time measurement.
    cpu_time.tick();
    double cta = cpu_time.accumulated();
    
    // Report results.
    Hermes::Mixins::Loggable::Static::info("ndof_coarse: %d + %d + %d + %d = %d", report_num_dofs(spaces));

    // Millipercent eigenvalue error w.r.t. the reference value (see physical_parameters.cpp). 
    double keff_err = 1e5*fabs(wf.get_keff() - REF_K_EFF)/REF_K_EFF;

    Hermes::Mixins::Loggable::Static::info("per-group err_est_coarse (H1): %g%%, %g%%, %g%%, %g%%", report_errors(h1_group_errors));
    Hermes::Mixins::Loggable::Static::info("per-group err_est_coarse (L2): %g%%, %g%%, %g%%, %g%%", report_errors(l2_group_errors));
    Hermes::Mixins::Loggable::Static::info("total err_est_coarse (H1): %g%%", h1_err_est);
    Hermes::Mixins::Loggable::Static::info("total err_est_coarse (L2): %g%%", l2_err_est);
    Hermes::Mixins::Loggable::Static::info("k_eff err: %g milli-percent", keff_err);

    // Add entry to DOF convergence graph.
    int ndof_coarse = spaces[0]->get_num_dofs() + spaces[1]->get_num_dofs() 
      + spaces[2]->get_num_dofs() + spaces[3]->get_num_dofs();
    graph_dof.add_values(0, ndof_coarse, h1_err_est);
    graph_dof.add_values(1, ndof_coarse, l2_err_est);
    graph_dof.add_values(2, ndof_coarse, keff_err);

    // Add entry to CPU convergence graph.
    graph_cpu.add_values(0, cta, h1_err_est);
    graph_cpu.add_values(1, cta, l2_err_est);
    graph_cpu.add_values(2, cta, keff_err);

    for (unsigned int g = 0; g < matprop.get_G(); g++)
      graph_dof_evol.add_values(g, as, Space<double>::get_num_dofs(spaces[g]));

    cpu_time.tick(Hermes::Mixins::TimeMeasurable::HERMES_SKIP);

    // If err_est too large, adapt the mesh (L2 norm chosen since (weighted integrals of) solution values
    // are more important for further analyses than the derivatives. 
    if (l2_err_est < ERR_STOP) 
      done = true;
    else 
    {
      Hermes::Mixins::Loggable::Static::info("Adapting the coarse mesh.");
      done = adapt_h1.adapt(selectors, THRESHOLD, STRATEGY, MESH_REGULARITY);
      if (spaces[0]->get_num_dofs() + spaces[1]->get_num_dofs() 
          + spaces[2]->get_num_dofs() + spaces[3]->get_num_dofs() >= NDOF_STOP) 
        done = true;
    }

    // Free reference meshes and spaces.
    for (unsigned int g = 0; g < matprop.get_G(); g++) 
    {
      delete ref_spaces_const[g];
      delete ref_meshes[g];
    }

    as++;
        
    if (as >= MAX_ADAPT_NUM) done = true;
  }
  while(done == false);

  Hermes::Mixins::Loggable::Static::info("Total running time: %g s", cpu_time.accumulated());
  
  for (unsigned int g = 0; g < matprop.get_G(); g++) 
  {
    delete spaces[g]; delete meshes[g];
    delete coarse_solutions[g], delete fine_solutions[g]; delete power_iterates[g];
  }
  
  delete mat;
  delete rhs;
  delete solver;

  graph_dof.save("conv_dof.gp");
  graph_cpu.save("conv_cpu.gp");
  graph_dof_evol.save("dof_evol.gp");

  // Wait for all views to be closed.
  View::wait();
  return 0;
}
Example #24
0
    bool NewtonSolver<Scalar>::solve_keep_jacobian(Scalar* coeff_vec, double newton_tol, int newton_max_iter, bool residual_as_function)
    {
      // Obtain the number of degrees of freedom.
      int ndof = this->dp->get_num_dofs();

      // The Newton's loop.
      double residual_norm;
      int it = 1;
      while (1)
      {
        // Assemble the residual vector.
        this->dp->assemble(coeff_vec, residual);

        // Measure the residual norm.
        if (residual_as_function)
        {
          // Prepare solutions for measuring residual norm.
          Hermes::vector<Solution<Scalar>*> solutions;
          Hermes::vector<bool> dir_lift_false;
          for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) {
            solutions.push_back(new Solution<Scalar>());
            dir_lift_false.push_back(false);
          }
          Solution<Scalar>::vector_to_solutions(residual, static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces(), solutions, dir_lift_false);

          // Calculate the norm.
          residual_norm = Global<Scalar>::calc_norms(solutions);

          // Clean up.
          for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
            delete solutions[i];
        }
        else 
        {
          // Calculate the l2-norm of residual vector, this is the traditional way.
          residual_norm = Global<Scalar>::get_l2_norm(residual);
        }

        // Info for the user.
        if(it == 1) 
        {
          if(this->verbose_output)
            info("---- Newton initial residual norm: %g", residual_norm);
        }
        else 
          if(this->verbose_output)
            info("---- Newton iter %d, residual norm: %g", it - 1, residual_norm);

        // If maximum allowed residual norm is exceeded, fail.
        if (residual_norm > max_allowed_residual_norm)
        {
          if (this->verbose_output)
          {
            info("Current residual norm: %g", residual_norm);
            info("Maximum allowed residual norm: %g", max_allowed_residual_norm);
            info("Newton solve not successful, returning false.");
          }
          break;
        }

        // If residual norm is within tolerance, return 'true'.
        // This is the only correct way of ending.
        if (residual_norm < newton_tol && it > 1) {
          // We want to return the solution in a different structure.
          this->sln_vector = new Scalar[ndof];
          for (int i = 0; i < ndof; i++)
            this->sln_vector[i] = coeff_vec[i];

          return true;
        }

        // Assemble and keep the jacobian if this has not been done before.
        // Also declare that LU-factorization in case of a direct solver will be done only once and reused afterwards.
        if(kept_jacobian == NULL) {
          kept_jacobian = create_matrix<Scalar>(this->matrix_solver_type);

          // Give the matrix solver the correct Jacobian. NOTE: It would be cleaner if the whole decision whether to keep 
          // Jacobian or not was made in the constructor.
          //
          // Delete the matrix solver created in the constructor.
          delete linear_solver; 
          // Create new matrix solver with correct matrix.
          linear_solver = create_linear_solver<Scalar>(this->matrix_solver_type, kept_jacobian, residual);
          
          this->dp->assemble(coeff_vec, kept_jacobian);
          linear_solver->set_factorization_scheme(HERMES_REUSE_FACTORIZATION_COMPLETELY);
        }

        // Multiply the residual vector with -1 since the matrix
        // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n).
        residual->change_sign();

        // Solve the linear system.
        if(!linear_solver->solve()) {
          if (this->verbose_output) 
            info ("Matrix<Scalar> solver failed. Returning false.\n");
          break;
        }

        // Add \deltaY^{n+1} to Y^n.
        for (int i = 0; i < ndof; i++)
          coeff_vec[i] += linear_solver->get_sln_vector()[i];

        // Increase the number of iterations and test if we are still under the limit.
        if (it++ >= newton_max_iter)
        {
          if (this->verbose_output) 
            info("Maximum allowed number of Newton iterations exceeded, returning false.");
          break;
        }
      }

      // Return false.
      // All 'bad' situations end here.
      return false;
    }
Example #25
0
    bool NewtonSolver<Scalar>::solve(Scalar* coeff_vec, double newton_tol, int newton_max_iter, bool residual_as_function)
    {      
      // Delete the old solution vector, if there is any.
      if(this->sln_vector != NULL)
      {
        delete [] this->sln_vector;
        this->sln_vector = NULL;
      }

      // Obtain the number of degrees of freedom.
      int ndof = this->dp->get_num_dofs();

      // The Newton's loop.
      double residual_norm;
      int it = 1;
      
      bool delete_timer = false;
      if (this->timer == NULL)
      {
        this->timer = new TimePeriod;
        delete_timer = true;
      }
            
      this->timer->tick();
      setup_time += this->timer->last();
      
      while (1)
      {        
        // Assemble just the residual vector.
        if(it > 1)
          static_cast<DiscreteProblem<Scalar>*>(this->dp)->temp_disable_adaptivity_cache();
        this->dp->assemble(coeff_vec, residual);
        
        this->timer->tick();
        assemble_time += this->timer->last();

        // Measure the residual norm.
        if (residual_as_function)
        {
          // Prepare solutions for measuring residual norm.
          Hermes::vector<Solution<Scalar>*> solutions;
          Hermes::vector<bool> dir_lift_false;
          for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) {
            solutions.push_back(new Solution<Scalar>());
            dir_lift_false.push_back(false);
          }
          Solution<Scalar>::vector_to_solutions(residual, static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces(), solutions, dir_lift_false);

          // Calculate the norm.
          residual_norm = Global<Scalar>::calc_norms(solutions);

          // Clean up.
          for (unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
            delete solutions[i];
        }
        else 
        {
          // Calculate the l2-norm of residual vector, this is the traditional way.
          residual_norm = Global<Scalar>::get_l2_norm(residual);
        }

        // Info for the user.
        if(it == 1) {
          if(this->verbose_output)
            info("---- Newton initial residual norm: %g", residual_norm);
        }
        else 
          if(this->verbose_output)
            info("---- Newton iter %d, residual norm: %g", it - 1, residual_norm);

        // If maximum allowed residual norm is exceeded, fail.
        if (residual_norm > max_allowed_residual_norm)
        {
          if (this->verbose_output)
          {
            info("Current residual norm: %g", residual_norm);
            info("Maximum allowed residual norm: %g", max_allowed_residual_norm);
            info("Newton solve not successful, returning false.");
          }
          break;
        }

        // If residual norm is within tolerance, return 'true'.
        // This is the only correct way of ending.
        if (residual_norm < newton_tol && it > 1) {
          // We want to return the solution in a different structure.
          this->sln_vector = new Scalar[ndof];
          for (int i = 0; i < ndof; i++)
            this->sln_vector[i] = coeff_vec[i];

          this->timer->tick();
          solve_time += this->timer->last();
          
          if (delete_timer)
          {
            delete this->timer;
            this->timer = NULL;
          }
          
          static_cast<DiscreteProblem<Scalar>*>(this->dp)->temp_enable_adaptivity_cache();

          return true;
        }
        
        this->timer->tick();
        solve_time += this->timer->last();

        // Assemble just the jacobian.
        this->dp->assemble(coeff_vec, jacobian);
        this->timer->tick();
        assemble_time += this->timer->last();

        // Multiply the residual vector with -1 since the matrix
        // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n).
        residual->change_sign();
        
        // Solve the linear system.
        if(!linear_solver->solve()) {
          if (this->verbose_output) 
            info ("Matrix<Scalar> solver failed. Returning false.\n");
          break;
        }
        
        // Add \deltaY^{n+1} to Y^n.
        for (int i = 0; i < ndof; i++)
          coeff_vec[i] += linear_solver->get_sln_vector()[i];

        // Increase the number of iterations and test if we are still under the limit.
        if (it++ >= newton_max_iter)
        {
          if (this->verbose_output) 
            info("Maximum allowed number of Newton iterations exceeded, returning false.");
          break;
        }
        
        this->timer->tick();
        solve_time += this->timer->last();
      }
      // Return false.
      // All 'bad' situations end here. 
      
      if (delete_timer)
      {
        delete this->timer;
        this->timer = NULL;
      }
      
      return false;
    }
Example #26
0
double KellyTypeAdapt::eval_interface_estimator(KellyTypeAdapt::ErrorEstimatorForm* err_est_form,
                                                RefMap *rm, SurfPos* surf_pos,
                                                LightArray<NeighborSearch*>& neighbor_searches, int neighbor_index)
{
  NeighborSearch* nbs = neighbor_searches.get(neighbor_index);
  Hermes::vector<MeshFunction*> slns;
  for (int i = 0; i < num; i++)
    slns.push_back(this->sln[i]);
  
  // Determine integration order.
  ExtData<Ord>* fake_ui = dp.init_ext_fns_ord(slns, neighbor_searches);
  
  // Order of additional external functions.
  // ExtData<Ord>* fake_ext = dp.init_ext_fns_ord(err_est_form->ext, nbs);

  // Order of geometric attributes (eg. for multiplication of a solution with coordinates, normals, etc.).
  Geom<Ord>* fake_e = new InterfaceGeom<Ord>(init_geom_ord(), nbs->neighb_el->marker, nbs->neighb_el->id, nbs->neighb_el->get_diameter());
  double fake_wt = 1.0;
  Ord o = err_est_form->ord(1, &fake_wt, fake_ui->fn, fake_ui->fn[err_est_form->i], fake_e, NULL);

  int order = rm->get_inv_ref_order();
  order += o.get_order();

  limit_order(order);

  // Clean up.
  if (fake_ui != NULL)
  {
    for (int i = 0; i < num; i++)
      delete fake_ui->fn[i];
    fake_ui->free_ord();
    delete fake_ui;
  }
  
  delete fake_e;
  
  //delete fake_ext;
  
  Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d();
  int eo = quad->get_edge_points(surf_pos->surf_num, order);
  int np = quad->get_num_points(eo);
  double3* pt = quad->get_points(eo);
  
  // Init geometry and jacobian*weights (do not use the NeighborSearch caching mechanism).
  double3* tan = rm->get_tangent(surf_pos->surf_num, eo);
  double* jwt = new double[np];
  for(int i = 0; i < np; i++)
    jwt[i] = pt[i][2] * tan[i][2];
  
  Geom<double>* e = new InterfaceGeom<double>(init_geom_surf(rm, surf_pos, eo), 
                                              nbs->neighb_el->marker, 
                                              nbs->neighb_el->id, 
                                              nbs->neighb_el->get_diameter());
    
  // function values
  ExtData<scalar>* ui = dp.init_ext_fns(slns, neighbor_searches, order);
  //ExtData<scalar>* ext = dp.init_ext_fns(err_est_form->ext, nbs);

  scalar res = interface_scaling_const *
                err_est_form->value(np, jwt, ui->fn, ui->fn[err_est_form->i], e, NULL);

  if (ui != NULL) { ui->free(); delete ui; }
  //if (ext != NULL) { ext->free(); delete ext; }
  e->free(); delete e;
  delete [] jwt;

  return std::abs(0.5*res);   // Edges are parameterized from 0 to 1 while integration weights
                              // are defined in (-1, 1). Thus multiplying with 0.5 to correct
                              // the weights.
}
Example #27
0
Adapt::Adapt(Hermes::vector< Space* > spaces_,
             Hermes::vector<ProjNormType> proj_norms) :
    num_act_elems(-1),
    have_errors(false),
    have_coarse_solutions(false),
    have_reference_solutions(false)
{
  // sanity check
  if (proj_norms.size() > 0 && spaces_.size() != proj_norms.size())
    error("Mismatched numbers of spaces and projection types in Adapt::Adapt().");

  this->num = spaces_.size();

  // sanity checks
  error_if(this->num <= 0, "Too few components (%d), only %d supported.", this->num, H2D_MAX_COMPONENTS);
  error_if(this->num > H2D_MAX_COMPONENTS, "Too many components (%d), only %d supported.", this->num, H2D_MAX_COMPONENTS);
  for (int i = 0; i < this->num; i++) {
    if (spaces_[i] == NULL) error("spaces[%d] is NULL in Adapt::Adapt().", i);
    this->spaces.push_back(spaces_[i]);
  }

  // reset values
  memset(errors, 0, sizeof(errors));
  memset(error_form, 0, sizeof(error_form));
  memset(error_ord, 0, sizeof(error_ord));
  memset(sln, 0, sizeof(sln));
  memset(rsln, 0, sizeof(rsln));

  // if norms were not set by the user, set them to defaults
  // according to spaces
  if (proj_norms.size() == 0) {
    for (int i = 0; i < this->num; i++) {
      switch (spaces[i]->get_type()) {
        case HERMES_H1_SPACE: proj_norms.push_back(HERMES_H1_NORM); break;
        case HERMES_HCURL_SPACE: proj_norms.push_back(HERMES_HCURL_NORM); break;
        case HERMES_HDIV_SPACE: proj_norms.push_back(HERMES_HDIV_NORM); break;
        case HERMES_L2_SPACE: proj_norms.push_back(HERMES_L2_NORM); break;
        default: error("Unknown space type in Adapt::Adapt().");
      }
    }
  }

  // assign norm weak forms  according to norms selection
  for (int i = 0; i < this->num; i++) {
    switch (proj_norms[i]) {
      case HERMES_H1_NORM:
           error_form[i][i] = h1_error_form<double, scalar>; error_ord[i][i] = h1_error_form<Ord, Ord>;
           //printf("H1 norm.\n");
           break;
      case HERMES_H1_SEMINORM:
           error_form[i][i] = h1_error_semi_form<double, scalar>; error_ord[i][i] = h1_error_semi_form<Ord, Ord>;
           //printf("H1 semi norm.\n");
           break;
      case HERMES_HCURL_NORM:
           error_form[i][i] = hcurl_error_form<double, scalar>; error_ord[i][i] = hcurl_error_form<Ord, Ord>;
           //printf("Hcurl norm.\n");
           break;
      case HERMES_HDIV_NORM:
           error_form[i][i] = hdiv_error_form<double, scalar>; error_ord[i][i] = hdiv_error_form<Ord, Ord>;
           //printf("Hdiv norm.\n");
           break;
      case HERMES_L2_NORM:
           error_form[i][i] = l2_error_form<double, scalar>; error_ord[i][i] = l2_error_form<Ord, Ord>;
	   //printf("L2 norm.\n");
           break;
      default: error("Unknown projection type in Adapt::Adapt().");
    }
  }
}
Example #28
0
void Adapt::fix_shared_mesh_refinements(Mesh** meshes, Hermes::vector<ElementToRefine>& elems_to_refine,
                                        int** idx, Hermes::vector<RefinementSelectors::Selector *> refinement_selectors) {
  int num_elem_to_proc = elems_to_refine.size();
  for(int inx = 0; inx < num_elem_to_proc; inx++) {
    ElementToRefine& elem_ref = elems_to_refine[inx];
    int current_quad_order = this->spaces[elem_ref.comp]->get_element_order(elem_ref.id);
    Element* current_elem = meshes[elem_ref.comp]->get_element(elem_ref.id);

    //select a refinement used by all components that share a mesh which is about to be refined
    int selected_refinement = elem_ref.split;
    for (int j = 0; j < this->num; j++)
    {
      if (selected_refinement == H2D_REFINEMENT_H) break; // iso refinement is max what can be recieved
      if (j != elem_ref.comp && meshes[j] == meshes[elem_ref.comp]) { // if a mesh is shared
        int ii = idx[elem_ref.id][j];
        if (ii >= 0) { // and the sample element is about to be refined by another compoment
          const ElementToRefine& elem_ref_ii = elems_to_refine[ii];
          if (elem_ref_ii.split != selected_refinement && elem_ref_ii.split != H2D_REFINEMENT_P) { //select more complicated refinement
            if ((elem_ref_ii.split == H2D_REFINEMENT_ANISO_H || elem_ref_ii.split == H2D_REFINEMENT_ANISO_V) && selected_refinement == H2D_REFINEMENT_P)
              selected_refinement = elem_ref_ii.split;
            else
              selected_refinement = H2D_REFINEMENT_H;
          }
        }
      }
    }

    //fix other refinements according to the selected refinement
    if (selected_refinement != H2D_REFINEMENT_P)
    {
      //get suggested orders for the selected refinement
      const int* suggested_orders = NULL;
      if (selected_refinement == H2D_REFINEMENT_H)
        suggested_orders = elem_ref.q;

      //update orders
      for (int j = 0; j < this->num; j++) {
        if (j != elem_ref.comp && meshes[j] == meshes[elem_ref.comp]) { // if components share the mesh
          // change currently processed refinement
          if (elem_ref.split != selected_refinement) {
            elem_ref.split = selected_refinement;
            refinement_selectors[j]->generate_shared_mesh_orders(current_elem, current_quad_order, elem_ref.split, elem_ref.p, suggested_orders);
          }

          // change other refinements
          int ii = idx[elem_ref.id][j];
          if (ii >= 0) {
            ElementToRefine& elem_ref_ii = elems_to_refine[ii];
            if (elem_ref_ii.split != selected_refinement) {
              elem_ref_ii.split = selected_refinement;
              refinement_selectors[j]->generate_shared_mesh_orders(current_elem, current_quad_order, elem_ref_ii.split, elem_ref_ii.p, suggested_orders);
            }
          }
          else { // element (of the other comp.) not refined at all: assign refinement
            ElementToRefine elem_ref_new(elem_ref.id, j);
            elem_ref_new.split = selected_refinement;
            refinement_selectors[j]->generate_shared_mesh_orders(current_elem, current_quad_order, elem_ref_new.split, elem_ref_new.p, suggested_orders);
            elems_to_refine.push_back(elem_ref_new);
          }
        }
      }
    }
  }
}
Example #29
0
int main(int argc, char* argv[])
{
  if (NUMBER_OF_EIGENVALUES > 6) error("Maximum number of eigenvalues is 6.");
  info("Desired number of eigenvalues: %d.", NUMBER_OF_EIGENVALUES);

  // Load the mesh.
  Mesh mesh;
  H2DReader mloader;
  mloader.load("../domain.mesh", &mesh);

  // Perform initial mesh refinements (optional).
  for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements();

  // Initialize boundary conditions. 
  DefaultEssentialBCConst bc_essential(Hermes::vector<std::string>(BDY_BOTTOM, BDY_RIGHT, BDY_TOP, BDY_LEFT), 0.0);
  EssentialBCs bcs(&bc_essential);

  // Create an H1 space with default shapeset.
  H1Space space(&mesh, &bcs, P_INIT);

  // Initialize the weak formulation.
  WeakFormEigenLeft wf_left;
  WeakFormEigenRight wf_right;

  // Initialize refinement selector.
  H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);

  // Initialize views.
  ScalarView sview_1("", new WinGeom(0, 0, 400, 360));
  sview_1.show_mesh(false);
  sview_1.fix_scale_width(60);
  ScalarView sview_2("", new WinGeom(405, 0, 400, 360));
  sview_2.show_mesh(false);
  sview_2.fix_scale_width(60);
  ScalarView sview_3("", new WinGeom(810, 0, 400, 360));
  sview_3.show_mesh(false);
  sview_3.fix_scale_width(60);
  ScalarView sview_4("", new WinGeom(0, 410, 400, 360));
  sview_4.show_mesh(false);
  sview_4.fix_scale_width(60);
  ScalarView sview_5("", new WinGeom(405, 410, 400, 360));
  sview_5.show_mesh(false);
  sview_5.fix_scale_width(60);
  ScalarView sview_6("", new WinGeom(810, 410, 400, 360));
  sview_6.show_mesh(false);
  sview_6.fix_scale_width(60);
  OrderView  oview("Polynomial orders", new WinGeom(1215, 0, 400, 360));

  // DOF and CPU convergence graphs.
  SimpleGraph graph_dof_est, graph_cpu_est;

  // Time measurement.
  TimePeriod cpu_time;
  cpu_time.tick();

  Solution sln[NUMBER_OF_EIGENVALUES], ref_sln[NUMBER_OF_EIGENVALUES];

  // Adaptivity loop:
  int as = 1;
  bool done = false;
  do
  {
    info("---- Adaptivity step %d:", as);
    info("Solving on reference mesh.");

    // Construct globally refined reference mesh and setup reference space.
    Space* ref_space = Space::construct_refined_space(&space);
    int ref_ndof = Space::get_num_dofs(ref_space);
    info("ref_ndof: %d.", ref_ndof);

    // Initialize matrices and matrix solver on referenc emesh.
    RCP<SparseMatrix> matrix_left = rcp(new CSCMatrix());
    RCP<SparseMatrix> matrix_right = rcp(new CSCMatrix());
    Solver* solver = create_linear_solver(matrix_solver, matrix_left.get());

    // Assemble the matrices on reference mesh.
    DiscreteProblem* dp_left = new DiscreteProblem(&wf_left, ref_space);
    dp_left->assemble(matrix_left.get());
    DiscreteProblem* dp_right = new DiscreteProblem(&wf_right, ref_space);
    dp_right->assemble(matrix_right.get());

    // Time measurement.
    cpu_time.tick();

    // Time measurement.
    cpu_time.tick(HERMES_SKIP);

    EigenSolver es(matrix_left, matrix_right);
    info("Calling Pysparse...");
    es.solve(NUMBER_OF_EIGENVALUES, TARGET_VALUE, TOL, MAX_ITER);
    info("Pysparse finished.");
    es.print_eigenvalues();

    // Initializing solution vector, solution and ScalarView.
    double* ref_coeff_vec;
    //Solution sln[NUMBER_OF_EIGENVALUES], ref_sln[NUMBER_OF_EIGENVALUES];
    //ScalarView view("Solution", new WinGeom(0, 0, 440, 350));

    // Reading solution vectors from file and visualizing.
    double eigenval[NUMBER_OF_EIGENVALUES];
    int neig = es.get_n_eigs();
    if (neig != NUMBER_OF_EIGENVALUES) error("Mismatched number of eigenvectors in the eigensolver output file.");  
    for (int ieig = 0; ieig < NUMBER_OF_EIGENVALUES; ieig++) {
      eigenval[ieig] = es.get_eigenvalue(ieig);
      int n;
      es.get_eigenvector(ieig, &ref_coeff_vec, &n);
      // Convert coefficient vector into a Solution.
      Solution::vector_to_solution(ref_coeff_vec, ref_space, &(ref_sln[ieig]));

      // Project the fine mesh solution onto the coarse mesh.
      info("Projecting reference solution %d on coarse mesh.", ieig);
      OGProjection::project_global(&space, &(ref_sln[ieig]), &(sln[ieig]), matrix_solver);
    }  

    // FIXME: Below, the adaptivity is done for the last eigenvector only,
    // this needs to be changed to take into account all eigenvectors.

    // View the coarse mesh solution and polynomial orders.
    
    //char title[100];
    //if (NUMBER_OF_EIGENVALUES > 0) {
    //  sprintf(title, "Solution 0, val = %g", eigenval[0]);
    //  sview_1.set_title(title);
    //  sview_1.show(&(sln[0]));
    //}
    //if (NUMBER_OF_EIGENVALUES > 1) {
    //  sprintf(title, "Solution 1, val = %g", eigenval[1]);
    //  sview_2.set_title(title);
    //  sview_2.show(&(sln[1]));
    //}
    //if (NUMBER_OF_EIGENVALUES > 2) {
    //  sprintf(title, "Solution 2, val = %g", eigenval[2]);
    //  sview_3.set_title(title);
    //  sview_3.show(&(sln[2]));
    //}
    //if (NUMBER_OF_EIGENVALUES > 3) {
    //  sprintf(title, "Solution 3, val = %g", eigenval[3]);
    //  sview_4.set_title(title);
    //  sview_4.show(&(sln[3]));
    //}
    //if (NUMBER_OF_EIGENVALUES > 4) {
    //  sprintf(title, "Solution 4, val = %g", eigenval[4]);
    //  sview_5.set_title(title);
    //  sview_5.show(&(sln[4]));
    //}
    //if (NUMBER_OF_EIGENVALUES > 5) {
    //  sprintf(title, "Solution 5, val = %g", eigenval[5]);
    //  sview_6.set_title(title);
    //  sview_6.show(&(sln[5]));
    //}
    //oview.show(&space);

    // Calculate element errors and total error estimate.
    info("Calculating error estimate.");
    Hermes::vector<Space *> spaces;
    for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++) spaces.push_back(&space);
    Adapt* adaptivity = new Adapt(spaces);
 
    Hermes::vector<Solution *> slns;
    if (NUMBER_OF_EIGENVALUES > 0) slns.push_back(&sln[0]);
    if (NUMBER_OF_EIGENVALUES > 1) slns.push_back(&sln[1]);
    if (NUMBER_OF_EIGENVALUES > 2) slns.push_back(&sln[2]);
    if (NUMBER_OF_EIGENVALUES > 3) slns.push_back(&sln[3]);
    if (NUMBER_OF_EIGENVALUES > 4) slns.push_back(&sln[4]);
    if (NUMBER_OF_EIGENVALUES > 5) slns.push_back(&sln[5]);
    
    Hermes::vector<Solution *> ref_slns;
    if (NUMBER_OF_EIGENVALUES > 0) ref_slns.push_back(&ref_sln[0]);
    if (NUMBER_OF_EIGENVALUES > 1) ref_slns.push_back(&ref_sln[1]);
    if (NUMBER_OF_EIGENVALUES > 2) ref_slns.push_back(&ref_sln[2]);
    if (NUMBER_OF_EIGENVALUES > 3) ref_slns.push_back(&ref_sln[3]);
    if (NUMBER_OF_EIGENVALUES > 4) ref_slns.push_back(&ref_sln[4]);
    if (NUMBER_OF_EIGENVALUES > 5) ref_slns.push_back(&ref_sln[5]);
    Hermes::vector<double> component_errors;
    double err_est_rel = adaptivity->calc_err_est(slns, ref_slns, &component_errors) * 100;

    // Report results.
    info("ndof_coarse: %d, ndof_fine: %d.", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space));
    if (NUMBER_OF_EIGENVALUES > 0) info("err_est_rel[0]: %g%%", component_errors[0] * 100);
    if (NUMBER_OF_EIGENVALUES > 1) info("err_est_rel[1]: %g%%", component_errors[1] * 100);
    if (NUMBER_OF_EIGENVALUES > 2) info("err_est_rel[2]: %g%%", component_errors[2] * 100);
    if (NUMBER_OF_EIGENVALUES > 3) info("err_est_rel[3]: %g%%", component_errors[3] * 100);
    if (NUMBER_OF_EIGENVALUES > 4) info("err_est_rel[4]: %g%%", component_errors[4] * 100);
    if (NUMBER_OF_EIGENVALUES > 5) info("err_est_rel[5]: %g%%", component_errors[5] * 100);
   
    // Time measurement.
    cpu_time.tick();

    // Add entry to DOF and CPU convergence graphs.
    graph_dof_est.add_values(Space::get_num_dofs(&space), err_est_rel);
    graph_dof_est.save("conv_dof_est.dat");
    graph_cpu_est.add_values(cpu_time.accumulated(), err_est_rel);
    graph_cpu_est.save("conv_cpu_est.dat");

    // Wait for keypress.
    //View::wait(HERMES_WAIT_KEYPRESS);

    // If err_est too large, adapt the mesh.
    if (err_est_rel < ERR_STOP) done = true;
    else
    {
      info("Adapting coarse mesh.");
      Hermes::vector<RefinementSelectors::Selector *> selectors;
      for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++)
        selectors.push_back(&selector);
      done = adaptivity->adapt(selectors, THRESHOLD, STRATEGY, MESH_REGULARITY);

      // Increase the counter of performed adaptivity steps.
      if (done == false)  as++;
    }
    if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true;

    // Clean up.
    delete solver;
    delete adaptivity;
    if(done == false) delete ref_space->get_mesh();
    delete ref_space;
    delete dp_left;
    delete dp_right;
  }
  while (done == false);

  int ndof = Space::get_num_dofs(&space);

  if (ndof < 450) {          // Was 401 when this test was created.
    printf("Success!\n");
    return ERR_SUCCESS;
  }
  else {
    printf("Failure!\n");
    return ERR_FAILURE;
  }

 
}
Example #30
0
bool rk_time_step(double current_time, double time_step, ButcherTable* const bt,
                  scalar* coeff_vec, scalar* err_vec, DiscreteProblem* dp, MatrixSolverType matrix_solver,
                  bool verbose, bool is_linear, double newton_tol, int newton_max_iter,
                  double newton_damping_coeff, double newton_max_allowed_residual_norm)
{
  // Check for not implemented features.
  if (matrix_solver != SOLVER_UMFPACK)
    error("Sorry, rk_time_step() still only works with UMFpack.");
  if (dp->get_weak_formulation()->get_neq() > 1)
    error("Sorry, rk_time_step() does not work with systems yet.");

  // Get number of stages from the Butcher's table.
  int num_stages = bt->get_size();

  // Check whether the user provided a second B-row if he wants 
  // err_vec.
  if(err_vec != NULL) {
    double b2_coeff_sum = 0;
    for (int i=0; i < num_stages; i++) b2_coeff_sum += fabs(bt->get_B2(i)); 
    if (b2_coeff_sum < 1e-10) 
      error("err_vec != NULL but the B2 row in the Butcher's table is zero in rk_time_step().");
  }

  // Matrix for the time derivative part of the equation (left-hand side).
  UMFPackMatrix* matrix_left = new UMFPackMatrix();

  // Matrix and vector for the rest (right-hand side).
  UMFPackMatrix* matrix_right = new UMFPackMatrix();
  UMFPackVector* vector_right = new UMFPackVector();

  // Create matrix solver.
  Solver* solver = create_linear_solver(matrix_solver, matrix_right, vector_right);

  // Get original space, mesh, and ndof.
  dp->get_space(0);
  Mesh* mesh = dp->get_space(0)->get_mesh();
  int ndof = dp->get_space(0)->get_num_dofs();

  // Create spaces for stage solutions. This is necessary
  // to define a num_stages x num_stages block weak formulation.
  Hermes::vector<Space*> stage_spaces;
  stage_spaces.push_back(dp->get_space(0));
  for (int i = 1; i < num_stages; i++) {
    stage_spaces.push_back(dp->get_space(0)->dup(mesh));
  }
  Space::assign_dofs(stage_spaces);

  // Create a multistage weak formulation.
  WeakForm stage_wf_left;                   // For the matrix M (size ndof times ndof).
  WeakForm stage_wf_right(num_stages);      // For the rest of equation (written on the right),
                                            // size num_stages*ndof times num_stages*ndof.
  create_stage_wf(current_time, time_step, bt, dp, &stage_wf_left, &stage_wf_right); 

  // Initialize discrete problems for the assembling of the
  // matrix M and the stage Jacobian matrix and residual.
  DiscreteProblem stage_dp_left(&stage_wf_left, dp->get_space(0));
  DiscreteProblem stage_dp_right(&stage_wf_right, stage_spaces);

  // Vector K_vector of length num_stages * ndof. will represent
  // the 'k_i' vectors in the usual R-K notation.
  scalar* K_vector = new scalar[num_stages*ndof];
  memset(K_vector, 0, num_stages * ndof * sizeof(scalar));

  // Vector u_prev_vec will represent y_n + h \sum_{j=1}^s a_{ij}k_i
  // in the usual R-K notation.
  scalar* u_prev_vec = new scalar[num_stages*ndof];

  // Vector for the left part of the residual.
  scalar* vector_left = new scalar[num_stages*ndof];

  // Prepare residuals of stage solutions.
  Hermes::vector<Solution*> residuals;
  Hermes::vector<bool> add_dir_lift;
  for (int i = 0; i < num_stages; i++) {
    residuals.push_back(new Solution(mesh));
    add_dir_lift.push_back(false);
  }

  // Assemble the block-diagonal mass matrix M of size ndof times ndof.
  // The corresponding part of the global residual vector is obtained 
  // just by multiplication.
  stage_dp_left.assemble(matrix_left);

  // The Newton's loop.
  double residual_norm;
  int it = 1;
  while (true)
  {
    // Prepare vector Y_n + h\sum_{j=1}^s a_{ij} K_j.
    for (int i = 0; i < num_stages; i++) {                // block row
      for (int idx = 0; idx < ndof; idx++) {
        scalar increment = 0;
        for (int j = 0; j < num_stages; j++) {
          increment += bt->get_A(i, j) * K_vector[j*ndof + idx];
        }
        u_prev_vec[i*ndof + idx] = coeff_vec[idx] + time_step * increment;
      }
    }

    multiply_as_diagonal_block_matrix(matrix_left, num_stages, 
                                      K_vector, vector_left);

    // Assemble the block Jacobian matrix of the stationary residual F
    // Diagonal blocks are created even if empty, so that matrix_left
    // can be added later.
    bool rhs_only = false;
    bool force_diagonal_blocks = true;
    stage_dp_right.assemble(u_prev_vec, matrix_right, vector_right,
                            rhs_only, force_diagonal_blocks);

    matrix_right->add_to_diagonal_blocks(num_stages, matrix_left);

    vector_right->add_vector(vector_left);

    // Multiply the residual vector with -1 since the matrix
    // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n).
    vector_right->change_sign();

    // Measure the residual norm.
    if (HERMES_RESIDUAL_AS_VECTOR_RK) {
      // Calculate the l2-norm of residual vector.
      residual_norm = get_l2_norm(vector_right);
    }
    else {
      // Translate residual vector into residual functions.
      Solution::vector_to_solutions(vector_right, stage_dp_right.get_spaces(),
                                    residuals, add_dir_lift);
      residual_norm = calc_norms(residuals);
    }

    // Info for the user.
    if (verbose) info("---- Newton iter %d, ndof %d, residual norm %g",
                      it, ndof, residual_norm);

    // If maximum allowed residual norm is exceeded, fail.
    if (residual_norm > newton_max_allowed_residual_norm) {
      if (verbose) {
        info("Current residual norm: %g", residual_norm);
        info("Maximum allowed residual norm: %g", newton_max_allowed_residual_norm);
        info("Newton solve not successful, returning false.");
      }
      return false;
    }

    // If residual norm is within tolerance, or the maximum number
    // of iteration has been reached, or the problem is linear, then quit.
    if ((residual_norm < newton_tol || it > newton_max_iter) && it > 1) break;

    // Solve the linear system.
    if(!solver->solve()) error ("Matrix solver failed.\n");

    // Add \deltaY^{n+1} to Y^n.
    for (int i = 0; i < num_stages*ndof; i++) {
      K_vector[i] += newton_damping_coeff * solver->get_solution()[i];
    }

    // If the problem is linear, quit.
    if (is_linear) {
      if (verbose) {
        info("Terminating Newton's loop as problem is linear.");
      }
      break;
    }

    // Increase iteration counter.
    it++;
  }

  // If max number of iterations was exceeded, fail.
  if (it >= newton_max_iter) {
    if (verbose) info("Maximum allowed number of Newton iterations exceeded, returning false.");
    return false;
  }

  // Calculate the vector \sum_{j=1}^s b_j k_j.
  Vector* rk_increment_vector = create_vector(matrix_solver);
  rk_increment_vector->alloc(ndof);
  for (int i = 0; i < ndof; i++) {
    rk_increment_vector->set(i, 0);
    for (int j = 0; j < num_stages; j++) {
      rk_increment_vector->add(i, bt->get_B(j) * K_vector[j*ndof + i]);
    }
  }

  // Calculate Y^{n+1} = Y^n + h \sum_{j=1}^s b_j k_j.
  for (int i = 0; i < ndof; i++) coeff_vec[i] += time_step * rk_increment_vector->get(i);

  // If err_vec is not NULL, use the second B-row in the Butcher's
  // table to calculate the second approximation Y_{n+1}. Then 
  // subtract the original one from it, and return this as an
  // error vector err_vec.
  if (err_vec != NULL) {
    for (int i = 0; i < ndof; i++) {
      rk_increment_vector->set(i, 0);
      for (int j = 0; j < num_stages; j++) {
        rk_increment_vector->add(i, bt->get_B2(j) * K_vector[j*ndof + i]);
      }
    }
    for (int i = 0; i < ndof; i++) err_vec[i] = time_step * rk_increment_vector->get(i);
    for (int i = 0; i < ndof; i++) err_vec[i] = err_vec[i] - coeff_vec[i];
  }

  // Clean up.
  delete matrix_left;
  delete matrix_right;
  delete vector_right;
  delete solver;
  delete rk_increment_vector;

  // Delete stage spaces, but not the first (original) one.
  for (int i = 1; i < num_stages; i++) delete stage_spaces[i];

  // Delete all residuals.
  for (int i = 0; i < num_stages; i++) delete residuals[i];

  // TODO: Delete stage_wf, in particular its external solutions
  // stage_time_sol[i], i = 0, 1, ..., num_stages-1.

  // Delete stage_vec and u_prev_vec.
  delete [] K_vector;
  delete [] u_prev_vec;

  // debug
  delete [] vector_left;

  return true;
}