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 }
// 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 }
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 }
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 }