Пример #1
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
}
Пример #2
0
// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

  // Skip adaptive examples on a non-adaptive libMesh build
#ifndef LIBMESH_ENABLE_AMR
  libmesh_example_assert(false, "--enable-amr");
#else

  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 << '[' << libMesh::processor_id() 
                  << "] 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);

  // Skip this default-2D example if libMesh was compiled as 1D-only.
  libmesh_example_assert(2 <= LIBMESH_DIM, "2D support");
  
  // Create a mesh.
  Mesh mesh;

  // And an object to refine it
  AutoPtr<MeshRefinement> mesh_refinement =
    build_mesh_refinement(mesh, param);

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

  std::cout << "Reading in and building the mesh" << std::endl;

   // Read in the mesh
  mesh.read(param.domainfile.c_str());
  // Make all the elements of the mesh second order so we can compute
  // with a higher order basis
  mesh.all_second_order();

  // Create a mesh refinement object to do the initial uniform refinements
  // on the coarse grid read in from lshaped.xda
  MeshRefinement initial_uniform_refinements(mesh);
  initial_uniform_refinements.uniformly_refine(param.coarserefinements);
    
  std::cout << "Building system" << std::endl;

  // Build the FEMSystem
  LaplaceSystem &system = equation_systems.add_system<LaplaceSystem> ("LaplaceSystem");

  // Set its parameters
  set_system_parameters(system, param);
  
  std::cout << "Initializing systems" << std::endl;

  equation_systems.init ();

  // Print information about the mesh and system to the screen.
  mesh.print_info();
  equation_systems.print_info();
  LinearSolver<Number> *linear_solver = system.get_linear_solver();

  {	
    // Adaptively solve the timestep
    unsigned int a_step = 0;
    for (; a_step != param.max_adaptivesteps; ++a_step)
      {	    	    
	// We can't adapt to both a tolerance and a
	// target mesh size
	if (param.global_tolerance != 0.)
	  libmesh_assert_equal_to (param.nelem_target, 0);
	// If we aren't adapting to a tolerance we need a
	// target mesh size
            else
              libmesh_assert_greater (param.nelem_target, 0);
    	
	linear_solver->reuse_preconditioner(false);

	// Solve the forward problem
	system.solve();

	// Write out the computed primal solution	
	write_output(equation_systems, a_step, "primal");
	
	// Get a pointer to the primal solution vector
	NumericVector<Number> &primal_solution = *system.solution;

	// Declare a QoISet object, we need this object to set weights for our QoI error contributions
	QoISet qois;

	// Declare a qoi_indices vector, each index will correspond to a QoI
	std::vector<unsigned int> qoi_indices;
	qoi_indices.push_back(0);
	qoi_indices.push_back(1);	
	qois.add_indices(qoi_indices);

	// Set weights for each index, these will weight the contribution of each QoI in the final error
	// estimate to be used for flagging elements for refinement
	qois.set_weight(0, 0.5);	
	qois.set_weight(1, 0.5);	

	// Make sure we get the contributions to the adjoint RHS from the sides
	system.assemble_qoi_sides = true;

	// We are about to solve the adjoint system, but before we do this we see the same preconditioner
	// flag to reuse the preconditioner from the forward solver		
	linear_solver->reuse_preconditioner(param.reuse_preconditioner);
	
	// Solve the adjoint system. This takes the transpose of the stiffness matrix and then
	// solves the resulting system
	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);

	// 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, a_step, "adjoint_0");

	// Swap back
	primal_solution.swap(dual_solution_0);
	
	// Get a pointer to the solution vector of the adjoint problem for QoI 0
	NumericVector<Number> &dual_solution_1 = system.get_adjoint_solution(1);
	
	// Swap again
	primal_solution.swap(dual_solution_1);	    
	write_output(equation_systems, a_step, "adjoint_1");

	// Swap back again
	primal_solution.swap(dual_solution_1);
				    
	std::cout << "Adaptive step " << a_step << ", we have " << mesh.n_active_elem()
                      << " active elements and "
                      << equation_systems.n_active_dofs()
		  << " active dofs." << std::endl ;

	// Postprocess, compute the approximate QoIs and write them out to the console
	std::cout << "Postprocessing: " << std::endl; 
	system.postprocess_sides = true;
	system.postprocess();
	Number QoI_0_computed = system.get_QoI_value("computed", 0);
	Number QoI_0_exact = system.get_QoI_value("exact", 0);
	Number QoI_1_computed = system.get_QoI_value("computed", 1);
	Number QoI_1_exact = system.get_QoI_value("exact", 1);
		
	std::cout<< "The relative error in QoI 0 is " << std::setprecision(17)
                 << std::abs(QoI_0_computed - QoI_0_exact) /
                    std::abs(QoI_0_exact) << std::endl;
		
	std::cout<< "The relative error in QoI 1 is " << std::setprecision(17) 
                 << std::abs(QoI_1_computed - QoI_1_exact) /
                    std::abs(QoI_1_exact) << std::endl << std::endl;
	
	// We will declare an error vector for passing to the adjoint refinement error estimator	
	ErrorVector QoI_elementwise_error;

	// Build an adjoint refinement error estimator object
	AutoPtr<AdjointRefinementEstimator> adjoint_refinement_error_estimator =
	  build_adjoint_refinement_error_estimator(qois);
	
	// Estimate the error in each element using the Adjoint Refinement estimator
	adjoint_refinement_error_estimator->estimate_error(system, QoI_elementwise_error);

	// Print out the computed error estimate, note that we access the global error estimates 
	// using an accessor function, right now sum(QoI_elementwise_error) != global_QoI_error_estimate
	std::cout<< "The computed relative error in QoI 0 is " << std::setprecision(17)
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) /
                    std::abs(QoI_0_exact) << std::endl;
		
	std::cout<< "The computed relative error in QoI 1 is " << std::setprecision(17) 
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) /
	  std::abs(QoI_1_exact) << std::endl << std::endl;

	// Also print out effecitivity indices (estimated error/true error)
	std::cout<< "The effectivity index for the computed error in QoI 0 is " << std::setprecision(17)
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) /
                    std::abs(QoI_0_computed - QoI_0_exact) << std::endl;

	std::cout<< "The effectivity index for the computed error in QoI 1 is " << std::setprecision(17)
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) /
	  std::abs(QoI_1_computed - QoI_1_exact) << std::endl << std::endl;
					    	    
	// We have to refine either based on reaching an error tolerance or 
	// a number of elements target, which should be verified above
	// Otherwise we flag elements by error tolerance or nelem target	  

	// Uniform refinement
	if(param.refine_uniformly)
	  {	  			    
	    mesh_refinement->uniformly_refine(1);
	  }
	// Adaptively refine based on reaching an error tolerance
	else if(param.global_tolerance >= 0. && param.nelem_target == 0.)
	  {	      	    
	    mesh_refinement->flag_elements_by_error_tolerance (QoI_elementwise_error);              
	    
	    mesh_refinement->refine_and_coarsen_elements();
	  }
	// Adaptively refine based on reaching a target number of elements
	else 
	  {	      	    	    
	    if (mesh.n_active_elem() >= param.nelem_target)
	      {
		std::cout<<"We reached the target number of elements."<<std::endl <<std::endl;
		break;
	      }				
	    
	    mesh_refinement->flag_elements_by_nelem_target (QoI_elementwise_error);
	    	    
	    mesh_refinement->refine_and_coarsen_elements();
	  }
            
	// Dont forget to reinit the system after each adaptive refinement !
	equation_systems.reinit();

        std::cout << "Refined mesh to "
                  << mesh.n_active_elem()
                  << " active elements and "
                  << equation_systems.n_active_dofs()
                  << " active dofs." << std::endl;
      }

    // Do one last solve if necessary
    if (a_step == param.max_adaptivesteps)
      {	 
	linear_solver->reuse_preconditioner(false);	
	system.solve();
	
	write_output(equation_systems, a_step, "primal");

	NumericVector<Number> &primal_solution = *system.solution;
	
	QoISet qois;
	std::vector<unsigned int> qoi_indices;

	qoi_indices.push_back(0);
	qoi_indices.push_back(1);	
	qois.add_indices(qoi_indices);
	
	qois.set_weight(0, 0.5);	
	qois.set_weight(1, 0.5);	

	system.assemble_qoi_sides = true;	
	linear_solver->reuse_preconditioner(param.reuse_preconditioner);
	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);

	NumericVector<Number> &dual_solution_0 = system.get_adjoint_solution(0);
	
	primal_solution.swap(dual_solution_0);	    
	write_output(equation_systems, a_step, "adjoint_0");

	primal_solution.swap(dual_solution_0);
	
	NumericVector<Number> &dual_solution_1 = system.get_adjoint_solution(1);
	
	primal_solution.swap(dual_solution_1);	    
	write_output(equation_systems, a_step, "adjoint_1");

	primal_solution.swap(dual_solution_1);
					
	std::cout << "Adaptive step " << a_step << ", we have " << mesh.n_active_elem()
		  << " active elements and "
		  << equation_systems.n_active_dofs()
		  << " active dofs." << std::endl ;	
	
	std::cout << "Postprocessing: " << std::endl; 
	system.postprocess_sides = true;
	system.postprocess();
	
	Number QoI_0_computed = system.get_QoI_value("computed", 0);
	Number QoI_0_exact = system.get_QoI_value("exact", 0);
	Number QoI_1_computed = system.get_QoI_value("computed", 1);
	Number QoI_1_exact = system.get_QoI_value("exact", 1);
	
	std::cout<< "The relative error in QoI 0 is " << std::setprecision(17)
                 << std::abs(QoI_0_computed - QoI_0_exact) /
                    std::abs(QoI_0_exact) << std::endl;
	
	std::cout<< "The relative error in QoI 1 is " << std::setprecision(17)
                 << std::abs(QoI_1_computed - QoI_1_exact) /
                    std::abs(QoI_1_exact) << std::endl << std::endl;

	// We will declare an error vector for passing to the adjoint refinement error estimator
	// Right now, only the first entry of this vector will be filled (with the global QoI error estimate)
	// Later, each entry of the vector will contain elementwise error that the user can sum to get the total error
	ErrorVector QoI_elementwise_error;

	// Build an adjoint refinement error estimator object
	AutoPtr<AdjointRefinementEstimator> adjoint_refinement_error_estimator =
	  build_adjoint_refinement_error_estimator(qois);
	
	// Estimate the error in each element using the Adjoint Refinement estimator
	adjoint_refinement_error_estimator->estimate_error(system, QoI_elementwise_error);

	// Print out the computed error estimate, note that we access the global error estimates 
	// using an accessor function, right now sum(QoI_elementwise_error) != global_QoI_error_estimate
	std::cout<< "The computed relative error in QoI 0 is " << std::setprecision(17)
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) /
                    std::abs(QoI_0_exact) << std::endl;
		
	std::cout<< "The computed relative error in QoI 1 is " << std::setprecision(17) 
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) /
	  std::abs(QoI_1_exact) << std::endl << std::endl;	

	// Also print out effecitivity indices (estimated error/true error)
	std::cout<< "The effectivity index for the computed error in QoI 0 is " << std::setprecision(17)
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) /
                    std::abs(QoI_0_computed - QoI_0_exact) << std::endl;

	std::cout<< "The effectivity index for the computed error in QoI 1 is " << std::setprecision(17)
                 << std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) /
	  std::abs(QoI_1_computed - QoI_1_exact) << std::endl << std::endl;

      }
  }

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

#endif // #ifndef LIBMESH_ENABLE_AMR
    
  // All done.  
  return 0;
}
Пример #3
0
// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

  // Skip adaptive examples on a non-adaptive libMesh build
#ifndef LIBMESH_ENABLE_AMR
  libmesh_example_assert(false, "--enable-amr");
#else
  // Only our PETSc interface currently supports adjoint solves
  libmesh_example_assert(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc");


  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 << '[' << libMesh::processor_id() 
                  << "] Can't find general.in; exiting early." 
                  << std::endl; 
        libmesh_error();
      }
  }
  GetPot infile("general.in");
  GetPot infile_l_shaped("l-shaped.in");

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

  // Skip this default-2D example if libMesh was compiled as 1D-only.
  libmesh_example_assert(2 <= LIBMESH_DIM, "2D support");
  
  // Create a mesh.
  Mesh mesh;

  // And an object to refine it
  AutoPtr<MeshRefinement> mesh_refinement =
    build_mesh_refinement(mesh, param);

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

  std::cout << "Reading in and building the mesh" << std::endl;

   // Read in the mesh
  mesh.read(param.domainfile.c_str());
  // Make all the elements of the mesh second order so we can compute
  // with a higher order basis
  mesh.all_second_order();

  // Create a mesh refinement object to do the initial uniform refinements
  // on the coarse grid read in from lshaped.xda
  MeshRefinement initial_uniform_refinements(mesh);
  initial_uniform_refinements.uniformly_refine(param.coarserefinements);
    
  std::cout << "Building system" << std::endl;

  // Build the FEMSystem
  LaplaceSystem &system = equation_systems.add_system<LaplaceSystem> ("LaplaceSystem");

  // Set its parameters
  set_system_parameters(system, param);
  
  std::cout << "Initializing systems" << std::endl;

  equation_systems.init ();

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

  {	
    // Adaptively solve the timestep
    unsigned int a_step = 0;
    for (; a_step != param.max_adaptivesteps; ++a_step)
      {	    	    
	// We can't adapt to both a tolerance and a
	// target mesh size
	if (param.global_tolerance != 0.)
	  libmesh_assert (param.nelem_target == 0);
	// If we aren't adapting to a tolerance we need a
	// target mesh size
            else
              libmesh_assert (param.nelem_target > 0);
    
	// Solve the forward problem
	system.solve();

	// Write out the computed primal solution	
	write_output(equation_systems, a_step, "primal");
	
	// Get a pointer to the primal solution vector
	NumericVector<Number> &primal_solution = *system.solution;
	
	// Declare a QoISet object, we need this object to set weights for our QoI error contributions
	QoISet qois;

	// Declare a qoi_indices vector, each index will correspond to a QoI
	std::vector<unsigned int> qoi_indices;
	qoi_indices.push_back(0);
	qoi_indices.push_back(1);
	qois.add_indices(qoi_indices);

	// Set weights for each index, these will weight the contribution of each QoI in the final error
	// estimate to be used for flagging elements for refinement
	qois.set_weight(0, 0.5);
	qois.set_weight(1, 0.5);

	// A SensitivityData object to hold the qois and parameters
	SensitivityData sensitivities(qois, system, system.get_parameter_vector());

	// Make sure we get the contributions to the adjoint RHS from the sides
	system.assemble_qoi_sides = true;

	// Compute the sensitivities
	system.adjoint_qoi_parameter_sensitivity(qois, system.get_parameter_vector(), sensitivities);

	GetPot infile("l-shaped.in");

	Number sensitivity_QoI_0_0_computed = sensitivities[0][0];
	Number sensitivity_QoI_0_0_exact = infile("sensitivity_0_0", 0.0);
	Number sensitivity_QoI_0_1_computed = sensitivities[0][1];
	Number sensitivity_QoI_0_1_exact = infile("sensitivity_0_1", 0.0);
		
	std::cout << "Adaptive step " << a_step << ", we have " << mesh.n_active_elem()
                      << " active elements and "
                      << equation_systems.n_active_dofs()
		  << " active dofs." << std::endl ;

	std::cout<<"Sensitivity of QoI one to Parameter one is "<<sensitivity_QoI_0_0_computed<<std::endl;
	std::cout<<"Sensitivity of QoI one to Parameter two is "<<sensitivity_QoI_0_1_computed<<std::endl;

	std::cout<< "The relative error in sensitivity QoI_0_0 is " 
		 << std::setprecision(17) 
                 << std::abs(sensitivity_QoI_0_0_computed - sensitivity_QoI_0_0_exact) /
                    std::abs(sensitivity_QoI_0_0_exact) << std::endl;
	std::cout<< "The relative error in sensitivity QoI_0_1 is " 
                 << std::setprecision(17) 
                 << std::abs(sensitivity_QoI_0_1_computed - sensitivity_QoI_0_1_exact) /
                    std::abs(sensitivity_QoI_0_1_exact) << std::endl << std::endl;						       			

	// 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, a_step, "adjoint_0");

	// Swap back
	primal_solution.swap(dual_solution_0);
					    										    	    
	// We have to refine either based on reaching an error tolerance or 
	// a number of elements target, which should be verified above
	// Otherwise we flag elements by error tolerance or nelem target	  

	// Uniform refinement
	if(param.refine_uniformly)
	  {	  			    
	    std::cout<<"Refining Uniformly"<<std::endl<<std::endl;

	    mesh_refinement->uniformly_refine(1);
	  }
	// Adaptively refine based on reaching an error tolerance
	else if(param.global_tolerance >= 0. && param.nelem_target == 0.)
	  {	      	    
	    // Now we construct the data structures for the mesh refinement process	
	    ErrorVector error;
	    
	    // Build an error estimator object
	    AutoPtr<ErrorEstimator> error_estimator =
	      build_error_estimator(param);

	    // Estimate the error in each element using the Adjoint Residual or Kelly error estimator
	    error_estimator->estimate_error(system, error);
	
	    mesh_refinement->flag_elements_by_error_tolerance (error);              
	    
	    mesh_refinement->refine_and_coarsen_elements();
	  }
	// Adaptively refine based on reaching a target number of elements
	else 
	  {
	    // Now we construct the data structures for the mesh refinement process	
	    ErrorVector error;
	    
	    // Build an error estimator object
	    AutoPtr<ErrorEstimator> error_estimator =
	      build_error_estimator(param);
	    
	    // Estimate the error in each element using the Adjoint Residual or Kelly error estimator
	    error_estimator->estimate_error(system, error);

	    if (mesh.n_active_elem() >= param.nelem_target)
	      {
		std::cout<<"We reached the target number of elements."<<std::endl <<std::endl;
		break;
	      }				
	    
	    mesh_refinement->flag_elements_by_nelem_target (error);
	    	    
	    mesh_refinement->refine_and_coarsen_elements();
	  }
            
	// Dont forget to reinit the system after each adaptive refinement !
	equation_systems.reinit();

        std::cout << "Refined mesh to "
                  << mesh.n_active_elem()
                  << " active elements and "
                  << equation_systems.n_active_dofs()
                  << " active dofs." << std::endl;
      }

    // Do one last solve if necessary
    if (a_step == param.max_adaptivesteps)
      {	    
	system.solve();
	
	write_output(equation_systems, a_step, "primal");

	NumericVector<Number> &primal_solution = *system.solution;
				     	
	QoISet qois;
	
	std::vector<unsigned int> qoi_indices;
	qoi_indices.push_back(0);
	qoi_indices.push_back(1);
	qois.add_indices(qoi_indices);
	
	qois.set_weight(0, 0.5);
	qois.set_weight(1, 0.5);
	
	SensitivityData sensitivities(qois, system, system.get_parameter_vector());
	
	system.assemble_qoi_sides = true;
	
	system.adjoint_qoi_parameter_sensitivity(qois, system.get_parameter_vector(), sensitivities);
	
	GetPot infile("l-shaped.in");

	Number sensitivity_QoI_0_0_computed = sensitivities[0][0];
	Number sensitivity_QoI_0_0_exact = infile("sensitivity_0_0", 0.0);
	Number sensitivity_QoI_0_1_computed = sensitivities[0][1];
	Number sensitivity_QoI_0_1_exact = infile("sensitivity_0_1", 0.0);
		
	std::cout << "Adaptive step " << a_step << ", we have " << mesh.n_active_elem()
		  << " active elements and "
		  << equation_systems.n_active_dofs()
		  << " active dofs." << std::endl ;	

	std::cout<<"Sensitivity of QoI one to Parameter one is "<<sensitivity_QoI_0_0_computed<<std::endl;
	std::cout<<"Sensitivity of QoI one to Parameter two is "<<sensitivity_QoI_0_1_computed<<std::endl;

	std::cout<< "The error in sensitivity QoI_0_0 is "
                 << std::setprecision(17)
                 << std::abs(sensitivity_QoI_0_0_computed - sensitivity_QoI_0_0_exact)/sensitivity_QoI_0_0_exact << std::endl;
	std::cout<< "The error in sensitivity QoI_0_1 is "
                 << std::setprecision(17)
                 << std::abs(sensitivity_QoI_0_1_computed - sensitivity_QoI_0_1_exact)/sensitivity_QoI_0_1_exact << std::endl << std::endl;
		
	NumericVector<Number> &dual_solution_0 = system.get_adjoint_solution(0);
	
	primal_solution.swap(dual_solution_0);	    
	write_output(equation_systems, a_step, "adjoint_0");

	primal_solution.swap(dual_solution_0);									
      }
  }

  std::cerr << '[' << libMesh::processor_id() 
            << "] Completing output." << std::endl; 
    
#endif // #ifndef LIBMESH_ENABLE_AMR
    
  // All done.  
  return 0;
}
Пример #4
0
// **********************************************************************
// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

  // Skip adaptive examples on a non-adaptive libMesh build
#ifndef LIBMESH_ENABLE_AMR
  libmesh_example_requires(false, "--enable-amr");
#else

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

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

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

  // Create a mesh, with dimension to be overridden later, distributed
  // across the default MPI communicator.
  Mesh mesh(init.comm());

  // And an object to refine it
  AutoPtr<MeshRefinement> mesh_refinement =
    build_mesh_refinement(mesh, param);

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

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

  MeshTools::Generation::build_square (mesh,
                                         20,
                                         20,
                                         0., 1.,
                                         0., 1.,
                                         QUAD9); //if changed, check pressure pinning

  // Create a mesh refinement object to do the initial uniform refinements
  //MeshRefinement initial_uniform_refinements(mesh);
  //initial_uniform_refinements.uniformly_refine(param.coarserefinements);

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

  // Build the FEMSystem
  ConvDiffSys &system = equation_systems.add_system<ConvDiffSys> ("ConvDiffSys");

  // Set its parameters
  set_system_parameters(system, param);

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

  equation_systems.init ();

  // Print information about the mesh and system to the screen.
  mesh.print_info();
  equation_systems.print_info();
  LinearSolver<Number> *linear_solver = system.get_linear_solver();

  {
    // Adaptively solve the timestep
    unsigned int a_step = 0;
    for (; a_step != param.max_adaptivesteps; ++a_step)
      {
        // We can't adapt to both a tolerance and a
        // target mesh size
        if (param.global_tolerance != 0.)
          libmesh_assert_equal_to (param.nelem_target, 0);
        // If we aren't adapting to a tolerance we need a
        // target mesh size
        else
          libmesh_assert_greater (param.nelem_target, 0);

        linear_solver->reuse_preconditioner(false); //can reuse for adjoint, but not for new forwards solve

        // Solve the forward problem
        system.solve();

        // Write out the computed primal solution
        write_output(equation_systems, a_step, "primal");

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

        // Declare a QoISet object, we need this object to set weights for our QoI error contributions
        QoISet qois;

        // Declare a qoi_indices vector, each index will correspond to a QoI
        std::vector<unsigned int> qoi_indices;
        qoi_indices.push_back(0);
        qois.add_indices(qoi_indices);

        // Set weights for each index, these will weight the contribution of each QoI in the final error
        // estimate to be used for flagging elements for refinement
        qois.set_weight(0, 1.0);

				// A SensitivityData object to hold the qois and parameters
        SensitivityData sensitivities_adj(qois, system, system.get_parameter_vector()); //use adjoint solve
        SensitivityData sensitivities_for(qois, system, system.get_parameter_vector()); //use forward solve

        // Make sure we get the contributions to the adjoint RHS from the sides
        system.assemble_qoi_sides = true; //does nothing anyways...

        // We are about to solve the adjoint system, but before we do this we see the same preconditioner
        // flag to reuse the preconditioner from the forward solver
        linear_solver->reuse_preconditioner(param.reuse_preconditioner);

        // Here we solve the adjoint problem inside the adjoint_qoi_parameter_sensitivity
        // function, so we have to set the adjoint_already_solved boolean to false
        system.set_adjoint_already_solved(false);

        // Compute the sensitivities
        system.adjoint_qoi_parameter_sensitivity(qois, system.get_parameter_vector(), sensitivities_adj);
        system.adjoint_qoi_parameter_sensitivity(qois, system.get_parameter_vector(), sensitivities_for);

        // 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);
        
        std::cout << "(Adjoint) Sensitivity of QoI to rho is " << sensitivities_adj[0][0] << std::endl;
        std::cout << "(Forward) Sensitivity of QoI to rho is " << sensitivities_for[0][0] << std::endl;

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

        // Swap the (pointers to) primal and dual solutions so we can write out the adjoint solution
        primal_solution.swap(dual_solution);
        write_output(equation_systems, a_step, "adjoint");

        // Swap back
        primal_solution.swap(dual_solution);

        std::cout << "Adaptive step " << a_step << ", we have " << mesh.n_active_elem()
                  << " active elements and "
                  << equation_systems.n_active_dofs()
                  << " active dofs." << std::endl ;

        // Postprocess, compute the approximate QoIs and write them out to the console
        std::cout << "Postprocessing: " << std::endl;
        system.postprocess_sides = false; //QoI doesn't involve edges
        system.postprocess();
        Number QoI_computed = system.get_QoI_value("computed", 0);

        std::cout<< "Computed QoI is " << std::setprecision(17)
                 << QoI_computed << std::endl;

        // Now we construct the data structures for the mesh refinement process
        ErrorVector error;

        // Build an error estimator object
        AutoPtr<ErrorEstimator> error_estimator =
          build_error_estimator(param, qois);

        // Estimate the error in each element using the Adjoint Residual or Kelly error estimator
        error_estimator->estimate_error(system, error);

        // We have to refine either based on reaching an error tolerance or
        // a number of elements target, which should be verified above
        // Otherwise we flag elements by error tolerance or nelem target

        // Uniform refinement
        if(param.refine_uniformly)
          {
            mesh_refinement->uniformly_refine(1);
          }
        // Adaptively refine based on reaching an error tolerance
        else if(param.global_tolerance >= 0. && param.nelem_target == 0.)
          {
            mesh_refinement->flag_elements_by_error_tolerance (error);

            mesh_refinement->refine_and_coarsen_elements();
          }
        // Adaptively refine based on reaching a target number of elements
        else
          {
            if (mesh.n_active_elem() >= param.nelem_target)
              {
                std::cout<<"We reached the target number of elements."<<std::endl <<std::endl;
                break;
              }

            mesh_refinement->flag_elements_by_nelem_target (error);

            mesh_refinement->refine_and_coarsen_elements();
          }

        // Dont forget to reinit the system after each adaptive refinement !
        equation_systems.reinit();

        std::cout << "Refined mesh to "
                  << mesh.n_active_elem()
                  << " active elements and "
                  << equation_systems.n_active_dofs()
                  << " active dofs." << std::endl;
      }

    // Do one last solve if necessary
    if (a_step == param.max_adaptivesteps)
      {
        linear_solver->reuse_preconditioner(false);
        system.solve();

        write_output(equation_systems, a_step, "primal");

        NumericVector<Number> &primal_solution = *system.solution;

        QoISet qois;
        std::vector<unsigned int> qoi_indices;

        qoi_indices.push_back(0);
        qois.add_indices(qoi_indices);
        qois.set_weight(0, 1.0);
        
        SensitivityData sensitivities_adj(qois, system, system.get_parameter_vector());
        SensitivityData sensitivities_for(qois, system, system.get_parameter_vector());

        system.assemble_qoi_sides = false; //QoI doesn't involve sides
        linear_solver->reuse_preconditioner(param.reuse_preconditioner);
        
        system.set_adjoint_already_solved(false);

        system.adjoint_qoi_parameter_sensitivity(qois, system.get_parameter_vector(), sensitivities_adj);
        system.forward_qoi_parameter_sensitivity(qois, system.get_parameter_vector(), sensitivities_for);

        // 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);
        
        std::cout << "(Adjoint) Sensitivity of QoI to rho is " << sensitivities_adj[0][0] << std::endl;
        std::cout << "(Forward) Sensitivity of QoI to rho is " << sensitivities_for[0][0] << std::endl;

        NumericVector<Number> &dual_solution = system.get_adjoint_solution(0);

        primal_solution.swap(dual_solution);
        write_output(equation_systems, a_step, "adjoint");
        primal_solution.swap(dual_solution);

        std::cout << "Adaptive step " << a_step << ", we have " << mesh.n_active_elem()
                  << " active elements and "
                  << equation_systems.n_active_dofs()
                  << " active dofs." << std::endl ;

        std::cout << "Postprocessing: " << std::endl;
        system.postprocess_sides = false; //nothing special on sides
        system.postprocess();

        Number QoI_computed = system.get_QoI_value("computed", 0);

        std::cout<< "Computed QoI is " << std::setprecision(17)
                 << QoI_computed << std::endl;
      }
  }

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

#endif // #ifndef LIBMESH_ENABLE_AMR

  // All done.
  return 0;
}