Example #1
0
LibMeshOperatorBase::LibMeshOperatorBase(
    const FunctionOperatorBuilder & builder, libMesh::MeshBase & m)
  : OperatorBase(),
    equation_systems(new libMesh::EquationSystems(m)),
    builder(builder)
{
#ifndef LIBMESH_HAVE_SLEPC
  if (m.processor_id() == 0)
    std::cerr << "ERROR: This example requires libMesh to be\n"
              << "compiled with SLEPc eigen solvers support!"
              << std::endl;
#else

#ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
  // SLEPc currently gives us a nasty crash with Real==float
  libmesh_example_assert(false, "--disable-singleprecision");
#endif

#ifdef LIBMESH_USE_COMPLEX_NUMBERS
  // SLEPc currently gives us an "inner product not well defined" with
  // Number==complex
  libmesh_example_assert(false, "--disable-complex");
#endif

  // Create a CondensedEigenSystem named "Eigensystem" and (for convenience)
  // use a reference to the system we create.
  this->equation_systems->add_system<libMesh::CondensedEigenSystem>("Eigensystem");

#endif // LIBMESH_HAVE_SLEPC
}
Example #2
0
// The main program.
int main (int argc, char** argv)
{
  // Skip adaptive examples on a non-adaptive libMesh build
#ifndef LIBMESH_ENABLE_AMR
  libmesh_example_assert(false, "--enable-amr");
#else
  // Skip this 2D example if libMesh was compiled as 1D-only.
  libmesh_example_assert(2 <= LIBMESH_DIM, "2D support");

  // Initialize libMesh.
  LibMeshInit init (argc, argv);

  std::cout << "Started " << argv[0] << std::endl;

  // Make sure the general input file exists, and parse it
  {
    std::ifstream i("general.in");
    if (!i)
      {
        std::cerr << '[' << init.comm().rank()
                  << "] Can't find general.in; exiting early."
                  << std::endl;
        libmesh_error();
      }
  }
  GetPot infile("general.in");

  // Read in parameters from the input file
  FEMParameters param;
  param.read(infile);

  // Create a mesh with the given dimension, distributed
  // across the default MPI communicator.
  Mesh mesh(init.comm(), param.dimension);

  // And an object to refine it
  AutoPtr<MeshRefinement> mesh_refinement(new MeshRefinement(mesh));

  // And an EquationSystems to run on it
  EquationSystems equation_systems (mesh);

  std::cout << "Building mesh" << std::endl;

  // Build a unit square
  ElemType elemtype;

  if (param.elementtype == "tri" ||
      param.elementtype == "unstructured")
    elemtype = TRI3;
  else
    elemtype = QUAD4;

  MeshTools::Generation::build_square
    (mesh, param.coarsegridx, param.coarsegridy,
     param.domain_xmin, param.domain_xmin + param.domain_edge_width,
     param.domain_ymin, param.domain_ymin + param.domain_edge_length,
     elemtype);

  std::cout << "Building system" << std::endl;

  HeatSystem &system = equation_systems.add_system<HeatSystem> ("HeatSystem");

  set_system_parameters(system, param);

  std::cout << "Initializing systems" << std::endl;

  // Initialize the system
  equation_systems.init ();

  // Refine the grid again if requested
  for (unsigned int i=0; i != param.extrarefinements; ++i)
    {
      mesh_refinement->uniformly_refine(1);
      equation_systems.reinit();
    }

  std::cout<<"Setting primal initial conditions"<<std::endl;

  read_initial_parameters();

  system.project_solution(initial_value, initial_grad,
                          equation_systems.parameters);

  // Output the H1 norm of the initial conditions
  libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl<<std::endl;

  // Add an adjoint vector, this will be computed after the forward
  // time stepping is complete
  //
  // Tell the library not to save adjoint solutions during the forward
  // solve
  //
  // Tell the library not to project this vector, and hence, memory
  // solution history to not save it.
  //
  // Make this vector ghosted so we can localize it to each element
  // later.
  const std::string & adjoint_solution_name = "adjoint_solution0";
  system.add_vector("adjoint_solution0", false, GHOSTED);

  // Close up any resources initial.C needed
  finish_initialization();

  // Plot the initial conditions
  write_output(equation_systems, 0, "primal");

  // Print information about the mesh and system to the screen.
  mesh.print_info();
  equation_systems.print_info();

  // In optimized mode we catch any solver errors, so that we can
  // write the proper footers before closing.  In debug mode we just
  // let the exception throw so that gdb can grab it.
#ifdef NDEBUG
  try
    {
#endif
      // Now we begin the timestep loop to compute the time-accurate
      // solution of the equations.
      for (unsigned int t_step=param.initial_timestep;
           t_step != param.initial_timestep + param.n_timesteps; ++t_step)
        {
          // A pretty update message
          std::cout << " Solving time step " << t_step << ", time = "
                    << system.time << std::endl;

          // Solve the forward problem at time t, to obtain the solution at time t + dt
          system.solve();

          // Output the H1 norm of the computed solution
          libMesh::out << "|U(" <<system.time + system.deltat<< ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl;

          // Advance to the next timestep in a transient problem
          std::cout<<"Advancing timestep"<<std::endl<<std::endl;
          system.time_solver->advance_timestep();

          // Write out this timestep
          write_output(equation_systems, t_step+1, "primal");
        }
      // End timestep loop

      ///////////////// Now for the Adjoint Solution //////////////////////////////////////

      // Now we will solve the backwards in time adjoint problem
      std::cout << std::endl << "Solving the adjoint problem" << std::endl;

      // We need to tell the library that it needs to project the adjoint, so
      // MemorySolutionHistory knows it has to save it

      // Tell the library to project the adjoint vector, and hence, memory solution history to
      // save it
      system.set_vector_preservation(adjoint_solution_name, true);

      std::cout << "Setting adjoint initial conditions Z("<<system.time<<")"<<std::endl;

      // Need to call adjoint_advance_timestep once for the initial condition setup
      std::cout<<"Retrieving solutions at time t="<<system.time<<std::endl;
      system.time_solver->adjoint_advance_timestep();

      // Output the H1 norm of the retrieved solutions (u^i and u^i+1)
      libMesh::out << "|U(" <<system.time + system.deltat<< ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl;

      libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl;

      // The first thing we have to do is to apply the adjoint initial
      // condition. The user should supply these. Here they are specified
      // in the functions adjoint_initial_value and adjoint_initial_gradient
      system.project_vector(adjoint_initial_value, adjoint_initial_grad, equation_systems.parameters, system.get_adjoint_solution(0));

      // Since we have specified an adjoint solution for the current time (T), set the adjoint_already_solved boolean to true, so we dont solve unneccesarily in the adjoint sensitivity method
      system.set_adjoint_already_solved(true);

      libMesh::out << "|Z(" <<system.time<< ")|= " << system.calculate_norm(system.get_adjoint_solution(), 0, H1) << std::endl<<std::endl;

      write_output(equation_systems, param.n_timesteps, "dual");

      // Now that the adjoint initial condition is set, we will start the
      // backwards in time adjoint integration

      // For loop stepping backwards in time
      for (unsigned int t_step=param.initial_timestep;
           t_step != param.initial_timestep + param.n_timesteps; ++t_step)
        {
          //A pretty update message
          std::cout << " Solving adjoint time step " << t_step << ", time = "
                    << system.time << std::endl;

          // The adjoint_advance_timestep
          // function calls the retrieve function of the memory_solution_history
          // class via the memory_solution_history object we declared earlier.
          // The retrieve function sets the system primal vectors to their values
          // at the current timestep
          std::cout<<"Retrieving solutions at time t="<<system.time<<std::endl;
          system.time_solver->adjoint_advance_timestep();

          // Output the H1 norm of the retrieved solution
          libMesh::out << "|U(" <<system.time + system.deltat << ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl;

          libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl;

          system.set_adjoint_already_solved(false);

          system.adjoint_solve();

          // Now that we have solved the adjoint, set the adjoint_already_solved boolean to true, so we dont solve unneccesarily in the error estimator
          system.set_adjoint_already_solved(true);

          libMesh::out << "|Z(" <<system.time<< ")|= "<< system.calculate_norm(system.get_adjoint_solution(), 0, H1) << std::endl << std::endl;

          // Get a pointer to the primal solution vector
          NumericVector<Number> &primal_solution = *system.solution;

          // Get a pointer to the solution vector of the adjoint problem for QoI 0
          NumericVector<Number> &dual_solution_0 = system.get_adjoint_solution(0);

          // Swap the primal and dual solutions so we can write out the adjoint solution
          primal_solution.swap(dual_solution_0);

          write_output(equation_systems, param.n_timesteps - (t_step + 1), "dual");

          // Swap back
          primal_solution.swap(dual_solution_0);
        }
      // End adjoint timestep loop

      // Now that we have computed both the primal and adjoint solutions, we compute the sensitivties to the parameter p
      // dQ/dp = partialQ/partialp - partialR/partialp
      // partialQ/partialp = (Q(p+dp) - Q(p-dp))/(2*dp), this is not supported by the library yet
      // partialR/partialp = (R(u,z;p+dp) - R(u,z;p-dp))/(2*dp), where
      // R(u,z;p+dp) = int_{0}^{T} f(z;p+dp) - <partialu/partialt, z>(p+dp) - <g(u),z>(p+dp)
      // To do this we need to step forward in time, and compute the perturbed R at each time step and accumulate it
      // Then once all time steps are over, we can compute (R(u,z;p+dp) - R(u,z;p-dp))/(2*dp)

      // Now we begin the timestep loop to compute the time-accurate
      // adjoint sensitivities
      for (unsigned int t_step=param.initial_timestep;
           t_step != param.initial_timestep + param.n_timesteps; ++t_step)
        {
          // A pretty update message
          std::cout << "Retrieving " << t_step << ", time = "
                    << system.time << std::endl;

          // Retrieve the primal and adjoint solutions at the current timestep
          system.time_solver->retrieve_timestep();

          libMesh::out << "|U(" <<system.time + system.deltat << ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl;

          libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl;

          libMesh::out << "|Z(" <<system.time<< ")|= "<< system.calculate_norm(system.get_adjoint_solution(0), 0, H1) << std::endl << std::endl;

          // Call the postprocess function which we have overloaded to compute
          // accumulate the perturbed residuals
          (dynamic_cast<HeatSystem&>(system)).perturb_accumulate_residuals(dynamic_cast<HeatSystem&>(system).get_parameter_vector());

          // Move the system time forward (retrieve_timestep does not do this)
          system.time += system.deltat;
        }

      // A pretty update message
      std::cout << "Retrieving " << " final time = "
                << system.time << std::endl;

      // Retrieve the primal and adjoint solutions at the current timestep
      system.time_solver->retrieve_timestep();

      libMesh::out << "|U(" <<system.time + system.deltat << ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl;

      libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl;

      libMesh::out << "|Z(" <<system.time<< ")|= "<< system.calculate_norm(system.get_adjoint_solution(0), 0, H1) << std::endl<<std::endl;

      // Call the postprocess function which we have overloaded to compute
      // accumulate the perturbed residuals
      (dynamic_cast<HeatSystem&>(system)).perturb_accumulate_residuals(dynamic_cast<HeatSystem&>(system).get_parameter_vector());

      // Now that we computed the accumulated, perturbed residuals, we can compute the
      // approximate sensitivity
      Number sensitivity_0_0 = (dynamic_cast<HeatSystem&>(system)).compute_final_sensitivity();

      // Print it out
      std::cout<<"Sensitivity of QoI 0 w.r.t parameter 0 is: " << sensitivity_0_0 << std::endl;

#ifdef NDEBUG
    }
  catch (...)
    {
      std::cerr << '[' << mesh.processor_id()
                << "] Caught exception; exiting early." << std::endl;
    }
#endif

  std::cerr << '[' << mesh.processor_id()
            << "] Completing output." << std::endl;

  // All done.
  return 0;

#endif // LIBMESH_ENABLE_AMR
}
Example #3
0
int main(int argc, char **argv)
{
#ifdef QUESO_HAVE_LIBMESH
  unsigned int i, j;
  QUESO::EnvOptionsValues opts;
  opts.m_seed = -1;

#ifdef QUESO_HAS_MPI
  MPI_Init(&argc, &argv);
  QUESO::FullEnvironment env(MPI_COMM_WORLD, "", "", &opts);
#else
  QUESO::FullEnvironment env("", "", &opts);
#endif

#ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
  // SLEPc currently gives us a nasty crash with Real==float
  libmesh_example_assert(false, "--disable-singleprecision");
#endif

// Need an artificial block here because libmesh needs to
// call PetscFinalize before we call MPI_Finalize
#ifdef LIBMESH_HAVE_SLEPC
{
  libMesh::LibMeshInit init(argc, argv);

  libMesh::Mesh mesh(init.comm());
  libMesh::MeshTools::Generation::build_square(mesh,
      20, 20, 0.0, 1.0, 0.0, 1.0, libMeshEnums::QUAD4);

  QUESO::FunctionOperatorBuilder builder;

  builder.order = "FIRST";
  builder.family = "LAGRANGE";
  builder.num_req_eigenpairs = 10;

  QUESO::LibMeshNegativeLaplacianOperator precision(builder, mesh);

  libMesh::EquationSystems & es = precision.get_equation_systems();
  libMesh::CondensedEigenSystem & eig_sys = es.get_system<libMesh::CondensedEigenSystem>(
      "Eigensystem");

  // Check all eigenfunctions have unit L2 norm
  std::vector<double> norms(builder.num_req_eigenpairs, 0);
  for (i = 0; i < builder.num_req_eigenpairs; i++) {
    eig_sys.get_eigenpair(i);
    norms[i] = eig_sys.calculate_norm(*eig_sys.solution,
                                      libMesh::SystemNorm(libMeshEnums::L2));
    if (abs(norms[i] - 1.0) > TEST_TOL) {
      return 1;
    }
  }

  const unsigned int dim = mesh.mesh_dimension();
  const libMesh::DofMap & dof_map = eig_sys.get_dof_map();
  libMesh::FEType fe_type = dof_map.variable_type(0);
  libMesh::AutoPtr<libMesh::FEBase> fe(libMesh::FEBase::build(dim, fe_type));
  libMesh::QGauss qrule(dim, libMeshEnums::FIFTH);
  fe->attach_quadrature_rule(&qrule);
  const std::vector<libMesh::Real> & JxW = fe->get_JxW();
  const std::vector<std::vector<libMesh::Real> >& phi = fe->get_phi();

  libMesh::AutoPtr<libMesh::NumericVector<libMesh::Real> > u, v;
  double ui = 0.0;
  double vj = 0.0;
  double ip = 0.0;

  for (i = 0; i < builder.num_req_eigenpairs - 1; i++) {
    eig_sys.get_eigenpair(i);
    u = eig_sys.solution->clone();
    for (j = i + 1; j < builder.num_req_eigenpairs; j++) {
      libMesh::MeshBase::const_element_iterator el = mesh.active_local_elements_begin();
      libMesh::MeshBase::const_element_iterator end_el = mesh.active_local_elements_end();
      eig_sys.get_eigenpair(j);
      v = eig_sys.solution->clone();
      for ( ; el != end_el; ++el) {
        const libMesh::Elem * elem = *el;
        fe->reinit(elem);
        for (unsigned int qp = 0; qp < qrule.n_points(); qp++) {
          for (unsigned int dof = 0; dof < phi.size(); dof++) {
            ui += (*u)(dof) * phi[dof][qp];
            vj += (*v)(dof) * phi[dof][qp];
          }
          ip += ui * vj * JxW[qp];
          ui = 0.0;
          vj = 0.0;
        }
      }
      std::cerr << "INTEGRAL of " << i << " against " << j << " is: " << ip << std::endl;
      if (abs(ip) > INTEGRATE_TOL) {
        return 1;
      }
      ip = 0.0;
    }
  }
}
#endif  // LIBMESH_HAVE_SLEPC
#ifdef QUESO_HAS_MPI
  MPI_Finalize();
#endif
  return 0;
#else
  return 77;
#endif
}
Example #4
0
int main(int argc, char **argv)
{
#ifdef QUESO_HAVE_LIBMESH
  unsigned int i;
  unsigned int j;
  const unsigned int num_pairs = 5;
  const unsigned int num_samples = 1e4;
  const double alpha = 3.0;
  const double beta = 1.0;
  QUESO::EnvOptionsValues opts;
  opts.m_seed = -1;

  MPI_Init(&argc, &argv);

  QUESO::FullEnvironment env(MPI_COMM_WORLD, "", "", &opts);

#ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
  // SLEPc farts with libMesh::Real==float
  libmesh_example_assert(false, "--disable-singleprecision");
#endif


// Need an artificial block here because libmesh needs to
// call PetscFinalize before we call MPI_Finalize
#ifdef LIBMESH_HAVE_SLEPC
{
  libMesh::LibMeshInit init(argc, argv);

  libMesh::Mesh mesh(init.comm());
  libMesh::MeshTools::Generation::build_square(mesh,
      20, 20, 0.0, 1.0, 0.0, 1.0, libMeshEnums::QUAD4);

  QUESO::FunctionOperatorBuilder fobuilder;

  fobuilder.order = "FIRST";
  fobuilder.family = "LAGRANGE";
  fobuilder.num_req_eigenpairs = num_pairs;

  QUESO::LibMeshFunction mean(fobuilder, mesh);
  QUESO::LibMeshNegativeLaplacianOperator precision(fobuilder, mesh);
  QUESO::InfiniteDimensionalGaussian mu(env, mean, precision, alpha, beta);

  // Vector to hold all KL coeffs
  std::vector<double> means(num_pairs, 0.0);
  std::vector<double> sumsqs(num_pairs, 0.0);
  std::vector<double> deltas(num_pairs, 0.0);
  double draw;

  for (i = 1; i < num_samples + 1; i++) {
    mu.draw();
    for (j = 0; j < num_pairs; j++) {
      draw = mu.get_kl_coefficient(j);
      deltas[j] = draw - means[j];
      means[j] += (double) deltas[j] / i;
      sumsqs[j] += deltas[j] * (draw - means[j]);
    }
    // std::cerr << "MEAN IS: " << means[0] << std::endl;
  }

  std::vector<double> vars(num_pairs, 0.0);
  for (j = 0; j < num_pairs; j++) {
    vars[j] = sumsqs[j] / (num_samples - 1);
  }

  double sigma = beta / std::pow(precision.get_eigenvalue(j), alpha / 2.0);
  double sigmasq = sigma * sigma;
  double mean_min;
  double mean_max;

  for (j = 0; j < num_pairs; j++) {
    // Mean is N(0, (lambda_j^{- alpha / 2} * beta)^2 / n)
    mean_min = -3.0 * sigma / std::sqrt(num_samples);
    mean_max =  3.0 * sigma / std::sqrt(num_samples);
    if (means[j] < mean_min || means[j] > mean_max) {
      std::cerr << "mean kl test failed" << std::endl;
      return 1;
    }
  }

  double var_min;
  double var_max;

  // var[j] should be approximately ~ N(sigma^2, 2 sigma^4 / (num_samples - 1))
  for (j = 0; j < num_pairs; j++) {
    var_min = sigmasq - 3.0 * sigmasq * std::sqrt(2.0 / (num_samples - 1));
    var_max = sigmasq + 3.0 * sigmasq * std::sqrt(2.0 / (num_samples - 1));
    if (vars[j] < var_min || vars[j] > var_max) {
      std::cerr << "variance kl test failed" << std::endl;
      return 1;
    }
  }
}
#endif  // LIBMESH_HAVE_SLEPC

  MPI_Finalize();
  return 0;
#else
  return 77;
#endif
}