예제 #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
int main(int argc, char** argv){

  //initialize libMesh
  LibMeshInit init(argc, argv);
  
  //parameters
  GetPot infile("fem_system_params.in");
  const bool transient                  = infile("transient", true);
  const Real deltat                     = infile("deltat", 0.005);
  unsigned int n_timesteps              = infile("n_timesteps", 20);
  const int nx                          = infile("nx",100);
  const int ny                          = infile("ny",100);
  const int nz                          = infile("nz",100);
  //const unsigned int dim                = 3;
  const unsigned int max_r_steps        = infile("max_r_steps", 3);
  const unsigned int max_r_level        = infile("max_r_level", 3);
  const Real refine_percentage          = infile("refine_percentage", 0.1);
  const Real coarsen_percentage         = infile("coarsen_percentage", 0.0);
  const std::string indicator_type      = infile("indicator_type", "kelly");
  const bool write_error                = infile("write_error",false);
  const bool flag_by_elem_frac          = infile("flag_by_elem_frac",true);
      
#ifdef LIBMESH_HAVE_EXODUS_API
  const unsigned int write_interval    = infile("write_interval", 5);
#endif

  // Create a mesh, with dimension to be overridden later, distributed
  // across the default MPI communicator.
  Mesh mesh(init.comm());
  
  //create mesh
  unsigned int dim;
  if(nz == 0){ //to check if oscillations happen in 2D as well...
    dim = 2;
    MeshTools::Generation::build_square(mesh, nx, ny, 497150.0, 501750.0, 537350.0, 540650.0, QUAD9);
  }else{
    dim = 3;
    MeshTools::Generation::build_cube(mesh, 
                                      nx, ny, nz, 
                                      497150.0, 501750.0, 
                                      537350.0, 540650.0, 
                                      0.0, 100.0, 
                                      HEX27);
  }
  
  // Print information about the mesh to the screen.
  mesh.print_info();
  
  // Create an equation systems object.
  EquationSystems equation_systems (mesh);
  
  //name system
  ContamTransSysInv & system = 
    equation_systems.add_system<ContamTransSysInv>("ContamTransInv");
    
  //solve as steady or transient
  if(transient){
    //system.time_solver = AutoPtr<TimeSolver>(new EulerSolver(system)); //backward Euler
    system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system));
    std::cout << "\n\nAaahhh transience not yet available!\n" << std::endl;
    n_timesteps = 1;
  }
  else{
    system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system));
    libmesh_assert_equal_to (n_timesteps, 1); //this doesn't seem to work?
  }
  
  // Initialize the system
  equation_systems.init ();
  
  //initial conditions
  read_initial_parameters();
  system.project_solution(initial_value, initial_grad,
                          equation_systems.parameters);
  finish_initialization();

  // Set the time stepping options...
  system.deltat = deltat;
  
  //...and the nonlinear solver options...
  NewtonSolver *solver = new NewtonSolver(system); 
  system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); 
  solver->quiet = infile("solver_quiet", true);
  solver->verbose = !solver->quiet;
  solver->max_nonlinear_iterations =
    infile("max_nonlinear_iterations", 15);
  solver->relative_step_tolerance =
    infile("relative_step_tolerance", 1.e-3);
  solver->relative_residual_tolerance =
    infile("relative_residual_tolerance", 0.0);
  solver->absolute_residual_tolerance =
    infile("absolute_residual_tolerance", 0.0);

  // And the linear solver options
  solver->max_linear_iterations           = infile("max_linear_iterations", 10000);
  solver->initial_linear_tolerance        = infile("initial_linear_tolerance",1.e-13);
  solver->minimum_linear_tolerance        = infile("minimum_linear_tolerance",1.e-13);
  solver->linear_tolerance_multiplier     = infile("linear_tolerance_multiplier",1.e-3);
    
  // Mesh Refinement object - to test effect of constant refined mesh (not refined at every timestep)
  MeshRefinement mesh_refinement(mesh);
  mesh_refinement.refine_fraction() = refine_percentage;
  mesh_refinement.coarsen_fraction() = coarsen_percentage;
  mesh_refinement.max_h_level() = max_r_level;

  // Print information about the system to the screen.
  equation_systems.print_info();
  
  ExodusII_IO exodusIO = ExodusII_IO(mesh); //for writing multiple timesteps to one file
  
  for (unsigned int r_step=0; r_step<max_r_steps; r_step++)
    {
      std::cout << "\nBeginning Solve " << r_step+1 << std::endl;
      
      for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
        {
      
          std::cout << "\n\nSolving time step " << t_step << ", time = "
                    << system.time << std::endl;
          
          system.solve();
          system.postprocess();
          
          // Advance to the next timestep in a transient problem
          system.time_solver->advance_timestep();
   
      } //end stepping through time loop
      
      std::cout << "\n  Refining the mesh..." << std::endl;
      
      // The \p ErrorVector is a particular \p StatisticsVector
      // for computing error information on a finite element mesh.
      ErrorVector error;
      
      if (indicator_type == "patch")
        {
          // The patch recovery estimator should give a
          // good estimate of the solution interpolation
          // error.
          PatchRecoveryErrorEstimator error_estimator;
          error_estimator.set_patch_reuse(false); //anisotropy trips up reuse
          error_estimator.estimate_error (system, error);
        }
      else if (indicator_type == "kelly")
        {

          // The Kelly error estimator is based on
          // an error bound for the Poisson problem
          // on linear elements, but is useful for
          // driving adaptive refinement in many problems
          KellyErrorEstimator error_estimator;

          error_estimator.estimate_error (system, error);
        }
      
      // Write out the error distribution
      if(write_error){
        std::ostringstream ss;
        ss << r_step;
#ifdef LIBMESH_HAVE_EXODUS_API
        std::string error_output = "error_"+ss.str()+".e";
#else
        std::string error_output = "error_"+ss.str()+".gmv";
#endif
        error.plot_error( error_output, mesh );
      }
      
      // This takes the error in \p error and decides which elements
      // will be coarsened or refined. 
      if(flag_by_elem_frac)
        mesh_refinement.flag_elements_by_elem_fraction(error);
      else
        mesh_refinement.flag_elements_by_error_fraction (error);
      
      // This call actually refines and coarsens the flagged
      // elements.
      mesh_refinement.refine_and_coarsen_elements();
      
      // This call reinitializes the \p EquationSystems object for
      // the newly refined mesh.  One of the steps in the
      // reinitialization is projecting the \p solution,
      // \p old_solution, etc... vectors from the old mesh to
      // the current one.
      equation_systems.reinit ();
      
      std::cout << "System has: " << equation_systems.n_active_dofs()
                << " degrees of freedom."
                << std::endl;

    } //end refinement loop
    
  //use that final refinement
  for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
    {
  
      std::cout << "\n\nSolving time step " << t_step << ", time = "
                << system.time << std::endl;
      
      system.solve();
      system.postprocess();
      
      Number QoI_computed = system.get_QoI_value("computed", 0);
      std::cout<< "Computed QoI is " << std::setprecision(17) << QoI_computed << std::endl;
      
      // Advance to the next timestep in a transient problem
      system.time_solver->advance_timestep();

    } //end stepping through time loop
    
    
#ifdef LIBMESH_HAVE_EXODUS_API
  for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
    {
      // Write out this timestep if we're requested to
      if ((t_step+1)%write_interval == 0)
        {
          std::ostringstream ex_file_name;
          std::ostringstream tplot_file_name;

          // We write the file in the ExodusII format.
          //ex_file_name << "out_"
          //            << std::setw(3)
          //            << std::setfill('0')
          //            << std::right
          //            << t_step+1
          //            << ".e";
                      
          tplot_file_name << "out_"
                      << std::setw(3)
                      << std::setfill('0')
                      << std::right
                      << t_step+1
                      << ".plt";

          //ExodusII_IO(mesh).write_timestep(ex_file_name.str(),
          //                                 equation_systems,
          //                                 1, /* This number indicates how many time steps
          //                                       are being written to the file */
          //                                 system.time);
          exodusIO.write_timestep("output.exo", equation_systems, t_step+1, system.time); //outputs all timesteps in one file
          TecplotIO(mesh).write_equation_systems(tplot_file_name.str(), equation_systems);
        }
    }
#endif // #ifdef LIBMESH_HAVE_EXODUS_API     

  // All done.
  return 0;
  
} //end main
예제 #3
0
int main(int argc, char** argv){

	//initialize libMesh
	LibMeshInit init(argc, argv);
	
	//parameters
	GetPot infile("fem_system_params.in");
  unsigned int n_timesteps             = infile("n_timesteps", 1);
  //Real init_dR                         = infile("init_dR",1.e-3);
  const int nx                          = infile("nx",100);
  const int ny                          = infile("ny",100);
  const int nz                          = infile("nz",100);
  GetPot infileForMesh("contamTrans.in");
  bool doContinuation                  = infileForMesh("do_continuation",false);
  bool doArcLengthContinuation         = infileForMesh("do_arclength_continuation",false);
  
  // Create a mesh, with dimension to be overridden later, distributed
  // across the default MPI communicator.
  Mesh mesh(init.comm());
  
  //create mesh
  unsigned int dim;
  if(nz == 0){ //to check if oscillations happen in 2D as well...
    dim = 2;
    MeshTools::Generation::build_square(mesh, nx, ny, 0., 2300., 0., 1650., QUAD9);
  }else{
    dim = 3;
    MeshTools::Generation::build_cube(mesh, 
                                      nx, ny, nz, 
                                      0., 2300., 
                                      0., 1650., 
                                      0., 100., 
                                      HEX27);
  }

  // Print information about the mesh to the screen.
  mesh.print_info(); //DEBUG

  // Create an equation systems object.
  EquationSystems equation_systems (mesh);
  
  //name system
  ContamTransSysInv & system = 
    equation_systems.add_system<ContamTransSysInv>("ContamTransInv");
  //system.min_continuation_parameter = 0.;
  //system.max_continuation_parameter = std::fabs(infileForMesh("reaction_rate",1.e-3));
  
  //steady-state problem	
 	system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system));
  libmesh_assert_equal_to (n_timesteps, 1);
  
  // Initialize the system
  equation_systems.init ();
  
  //initial conditions
  read_initial_parameters();
  system.project_solution(initial_value, initial_grad,
                          equation_systems.parameters);
  finish_initialization();

  // And the nonlinear solver options
  NewtonSolver *solver = new NewtonSolver(system); 
  system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); 
  solver->quiet = infile("solver_quiet", true);
  solver->verbose = !solver->quiet;
  solver->max_nonlinear_iterations =
    infile("max_nonlinear_iterations", 15);
  solver->relative_step_tolerance =
    infile("relative_step_tolerance", 1.e-3);
  solver->relative_residual_tolerance =
    infile("relative_residual_tolerance", 0.0);
  solver->absolute_residual_tolerance =
    infile("absolute_residual_tolerance", 0.0);

  // And the linear solver options
  solver->max_linear_iterations           = infile("max_linear_iterations", 10000);
  solver->initial_linear_tolerance        = infile("initial_linear_tolerance",1.e-13);
  solver->minimum_linear_tolerance        = infile("minimum_linear_tolerance",1.e-13);
  solver->linear_tolerance_multiplier     = infile("linear_tolerance_multiplier",1.e-3);

  // Print information about the system to the screen.
  equation_systems.print_info(); //DEBUG
  
  Real target_R = infileForMesh("reaction_rate",1.e-3);
  
  if(!doContinuation){
    system.set_R(target_R);
    system.solve();
  }else if(doArcLengthContinuation){
  
    std::cout << "\n\nAAAAAAAAAAAAAHHHHHHHHH this arc-length continuation doesn't work yet...\n\n" << std::endl;
    /*
    system.quiet = infile("solver_quiet", true);
    system.set_max_arclength_stepsize(infile("max_ds",1.e2));
      
    //two prior solutions
    system.set_R(0.); 
    system.solve(); //first solution
    system.save_current_solution();
    std::cout << "\n First solve finished..." << std::endl;
    system.set_R(init_dR);
    system.solve(); //second solution
    std::cout << "\n Second solve finished..." << std::endl;
    
    //continuation steps
    //system.set_R(target_R);
    system.continuation_solve(); //doesn't seem to move away first step...what is this even supposed to do?
    std::cout << "\n Continuation solve done..." << std::endl;
    Real Rcurr = system.get_R();
    int iter = 0;
    while(system.get_R() < 0.99*target_R && iter < infile("max_arcsteps",10)){
      system.advance_arcstep();
      system.solve();
      std::cout << "\nR: " << system.get_R() << std::endl;
      std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
      std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
      std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
      iter += 1;
    }
    */
  }else{ //natural continuation
    std::vector<double> Rsteps;
    if(FILE *fp=fopen("continuation_steps.txt","r")){
			Real value;
			int flag = 1;
			while(flag != -1){
				flag = fscanf(fp,"%lf",&value);
				if(flag != -1){
					Rsteps.push_back(value);
				}
			}
			fclose(fp);
	  }else{
	    std::cout << "\n\n Need to define continuation steps in continuation_steps.txt\n\n" << std::endl;
	  }
	  
	  for(int i = 0; i < Rsteps.size(); i++){
	    double R = Rsteps[i];
	    system.set_R(R);
	    std::cout << "\n\nStarting iteration with R = " << R << "\n\n" << std::endl;
	    system.solve();
	  }
  } //end continuation type switch
  
  system.postprocess();
  Number QoI_computed = system.get_QoI_value("computed", 0);
  std::cout<< "Computed QoI is " << std::setprecision(17) << QoI_computed << std::endl;

  // All done.
  return 0;
  
} //end main
예제 #4
0
// The main program
int main(int argc, char** argv)
{
  //for record-keeping
  std::cout << "Running: " << argv[0];
  for (int i=1; i<argc; i++)
    std::cout << " " << argv[i];
  std::cout << std::endl << std::endl;

  clock_t begin = std::clock();
  
  // Initialize libMesh
  LibMeshInit init(argc, argv);
  
  // Parameters
  GetPot solverInfile("fem_system_params.in");
  const bool transient                  = solverInfile("transient", false);
  unsigned int n_timesteps              = solverInfile("n_timesteps", 1);
  const int nx                          = solverInfile("nx",100);
  const int ny                          = solverInfile("ny",100);
  const int nz                          = solverInfile("nz",100);
  GetPot infile("contamTrans.in");
  //std::string find_mesh_here            = infile("initial_mesh","mesh.exo");
  bool doContinuation                   = infile("do_continuation",false);
  bool splitSuperAdj                    = infile("split_super_adjoint",true); //solve as single adjoint or two forwards
  int maxIter                           = infile("max_model_refinements",0);  //maximum number of model refinements
  double refStep                        = infile("refinement_step",0.1); //additional proportion of domain refined per step
    //this refers to additional basis functions...number of elements will be more...
  double qoiErrorTol                    = infile("relative_error_tolerance",0.01); //stopping criterion
  //bool doDivvyMatlab                    = infile("do_divvy_in_Matlab",false); //output files to determine next refinement in Matlab
  bool avoid_sides                      = infile("avoid_sides",false); //DEBUG, whether to avoid sides while refining

  if(refStep*maxIter > 1)
    maxIter = round(ceil(1./refStep));

  Mesh mesh(init.comm());
  Mesh mesh2(init.comm()); 
  
  //create mesh
  unsigned int dim;
  if(nz == 0){ //to check if oscillations happen in 2D as well...
    dim = 2;
    MeshTools::Generation::build_square(mesh, nx, ny, 0., 2300., 0., 1650., QUAD9);
    MeshTools::Generation::build_square(mesh2, nx, ny, 0., 2300., 0., 1650., QUAD9);
  }else{
    dim = 3;
    MeshTools::Generation::build_cube(mesh, nx, ny, nz, 0., 2300., 0., 1650., 0., 100., HEX27);
    MeshTools::Generation::build_cube(mesh2, nx, ny, nz, 0., 2300., 0., 1650., 0., 100., HEX27);
  }
  
  mesh.print_info(); //DEBUG
  
  // Create an equation systems object.
  EquationSystems equation_systems (mesh);
  EquationSystems equation_systems_mix(mesh2);
  
  //name system
  ConvDiff_PrimarySys & system_primary = 
    equation_systems.add_system<ConvDiff_PrimarySys>("ConvDiff_PrimarySys"); //for primary variables
  ConvDiff_AuxSys & system_aux = 
    equation_systems.add_system<ConvDiff_AuxSys>("ConvDiff_AuxSys"); //for auxiliary variables
  ConvDiff_MprimeSys & system_mix = 
    equation_systems_mix.add_system<ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys"); //for superadj
  ConvDiff_PrimarySadjSys & system_sadj_primary = 
    equation_systems.add_system<ConvDiff_PrimarySadjSys>("ConvDiff_PrimarySadjSys"); //for split superadj
  ConvDiff_AuxSadjSys & system_sadj_aux = 
    equation_systems.add_system<ConvDiff_AuxSadjSys>("ConvDiff_AuxSadjSys"); //for split superadj
    
  //steady-state problem  
  system_primary.time_solver =
    AutoPtr<TimeSolver>(new SteadySolver(system_primary));
  system_aux.time_solver =
    AutoPtr<TimeSolver>(new SteadySolver(system_aux));
  system_mix.time_solver =
    AutoPtr<TimeSolver>(new SteadySolver(system_mix));
  system_sadj_primary.time_solver =
    AutoPtr<TimeSolver>(new SteadySolver(system_sadj_primary));
  system_sadj_aux.time_solver =
    AutoPtr<TimeSolver>(new SteadySolver(system_sadj_aux));
  libmesh_assert_equal_to (n_timesteps, 1);
  
  // Initialize the system
  equation_systems.init ();
  equation_systems_mix.init();
  
  //initial guess for primary state
  read_initial_parameters();
  system_primary.project_solution(initial_value, initial_grad,
                          equation_systems.parameters);
  finish_initialization();

  //nonlinear solver options
  NewtonSolver *solver_sadj_primary = new NewtonSolver(system_sadj_primary); 
  system_sadj_primary.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_sadj_primary); 
  solver_sadj_primary->quiet = solverInfile("solver_quiet", true);
  solver_sadj_primary->verbose = !solver_sadj_primary->quiet;
  solver_sadj_primary->max_nonlinear_iterations =
    solverInfile("max_nonlinear_iterations", 15);
  solver_sadj_primary->relative_step_tolerance =
    solverInfile("relative_step_tolerance", 1.e-3);
  solver_sadj_primary->relative_residual_tolerance =
    solverInfile("relative_residual_tolerance", 0.0);
  solver_sadj_primary->absolute_residual_tolerance =
    solverInfile("absolute_residual_tolerance", 0.0);
  NewtonSolver *solver_sadj_aux = new NewtonSolver(system_sadj_aux); 
  system_sadj_aux.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_sadj_aux); 
  solver_sadj_aux->quiet = solverInfile("solver_quiet", true);
  solver_sadj_aux->verbose = !solver_sadj_aux->quiet;
  solver_sadj_aux->max_nonlinear_iterations =
    solverInfile("max_nonlinear_iterations", 15);
  solver_sadj_aux->relative_step_tolerance =
    solverInfile("relative_step_tolerance", 1.e-3);
  solver_sadj_aux->relative_residual_tolerance =
    solverInfile("relative_residual_tolerance", 0.0);
  solver_sadj_aux->absolute_residual_tolerance =
    solverInfile("absolute_residual_tolerance", 0.0);
  NewtonSolver *solver_primary = new NewtonSolver(system_primary); 
  system_primary.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_primary); 
  solver_primary->quiet = solverInfile("solver_quiet", true);
  solver_primary->verbose = !solver_primary->quiet;
  solver_primary->max_nonlinear_iterations =
    solverInfile("max_nonlinear_iterations", 15);
  solver_primary->relative_step_tolerance =
    solverInfile("relative_step_tolerance", 1.e-3);
  solver_primary->relative_residual_tolerance =
    solverInfile("relative_residual_tolerance", 0.0);
  solver_primary->absolute_residual_tolerance =
    solverInfile("absolute_residual_tolerance", 0.0);
  NewtonSolver *solver_aux = new NewtonSolver(system_aux); 
  system_aux.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_aux); 
  solver_aux->quiet = solverInfile("solver_quiet", true);
  solver_aux->verbose = !solver_aux->quiet;
  solver_aux->max_nonlinear_iterations =
    solverInfile("max_nonlinear_iterations", 15);
  solver_aux->relative_step_tolerance =
    solverInfile("relative_step_tolerance", 1.e-3);
  solver_aux->relative_residual_tolerance =
    solverInfile("relative_residual_tolerance", 0.0);
  solver_aux->absolute_residual_tolerance =
    solverInfile("absolute_residual_tolerance", 0.0);
  solver_primary->require_residual_reduction = solverInfile("require_residual_reduction",true);
  solver_sadj_primary->require_residual_reduction = solverInfile("require_residual_reduction",true);
  solver_aux->require_residual_reduction = solverInfile("require_residual_reduction",true);
  solver_sadj_aux->require_residual_reduction = solverInfile("require_residual_reduction",true);  
  
  //linear solver options
  solver_primary->max_linear_iterations       = solverInfile("max_linear_iterations",10000);
  solver_primary->initial_linear_tolerance    = solverInfile("initial_linear_tolerance",1.e-13);
  solver_primary->minimum_linear_tolerance    = solverInfile("minimum_linear_tolerance",1.e-13);
  solver_primary->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3);
  solver_aux->max_linear_iterations           = solverInfile("max_linear_iterations",10000);
  solver_aux->initial_linear_tolerance        = solverInfile("initial_linear_tolerance",1.e-13);
  solver_aux->minimum_linear_tolerance        = solverInfile("minimum_linear_tolerance",1.e-13);
  solver_aux->linear_tolerance_multiplier     = solverInfile("linear_tolerance_multiplier",1.e-3);
  solver_sadj_primary->max_linear_iterations       = solverInfile("max_linear_iterations",10000);
  solver_sadj_primary->initial_linear_tolerance    = solverInfile("initial_linear_tolerance",1.e-13);
  solver_sadj_primary->minimum_linear_tolerance    = solverInfile("minimum_linear_tolerance",1.e-13);
  solver_sadj_primary->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3);
  solver_sadj_aux->max_linear_iterations           = solverInfile("max_linear_iterations",10000);
  solver_sadj_aux->initial_linear_tolerance        = solverInfile("initial_linear_tolerance",1.e-13);
  solver_sadj_aux->minimum_linear_tolerance        = solverInfile("minimum_linear_tolerance",1.e-13);
  solver_sadj_aux->linear_tolerance_multiplier     = solverInfile("linear_tolerance_multiplier",1.e-3);
  
  /*if(doDivvyMatlab){
    //DOF maps and such to help visualize
    std::ofstream output_global_dof("global_dof_map.dat");
    for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){
      std::vector< dof_id_type > di;
      system_mix.get_dof_map().dof_indices(system_mix.get_mesh().elem(i), di);
      if(output_global_dof.is_open()){
        output_global_dof << i << " ";
        for(unsigned int j = 0; j < di.size(); j++)
          output_global_dof << di[j] << " ";
        output_global_dof << "\n";
      }
    }
    output_global_dof.close();
    std::ofstream output_elem_cent("elem_centroids.dat");
    for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){
      Point elem_cent = system_mix.get_mesh().elem(i)->centroid();
      if(output_elem_cent.is_open()){
        output_elem_cent << elem_cent(0) << " " << elem_cent(1) << "\n";
      }
    }
    output_elem_cent.close();
  }*/
  
  //inverse dof map (elements in support of each node, assuming every 6 dofs belong to same node)
  std::vector<std::set<dof_id_type> > node_to_elem; 
  node_to_elem.resize(round(system_mix.n_dofs()/6.));
  for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){
    std::vector< dof_id_type > di;
    system_mix.get_dof_map().dof_indices(system_mix.get_mesh().elem(i), di);
    for(unsigned int j = 0; j < di.size(); j++)
      node_to_elem[round(floor(di[j]/6.))].insert(i);
  }

  int refIter = 0;
  double relError = 2.*qoiErrorTol;
  while(refIter <= maxIter && relError > qoiErrorTol){
    if(!doContinuation){ //clear out previous solutions
      system_primary.solution->zero();
      system_aux.solution->zero();
      system_sadj_primary.solution->zero();
      system_sadj_aux.solution->zero();
    }
    system_mix.solution->zero();
    
    clock_t begin_inv = std::clock();
    system_primary.solve();
    system_primary.clearQoI();
    clock_t end_inv = std::clock();
    clock_t begin_err_est = std::clock();
    std::cout << "\n End primary solve, begin auxiliary solve..." << std::endl;
    system_aux.solve();
    std::cout << "\n End auxiliary solve..." << std::endl;
    clock_t end_aux = std::clock();
    
    system_primary.postprocess();
    system_aux.postprocess();
    
    system_sadj_primary.set_c_vals(system_primary.get_c_vals());
    system_sadj_aux.set_auxc_vals(system_aux.get_auxc_vals());

    equation_systems_mix.reinit();
    //combine primary and auxiliary variables into psi
    DirectSolutionTransfer sol_transfer(init.comm()); 
    sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_c")),
      system_mix.variable(system_mix.variable_number("aux_c")));
    sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_zc")),
      system_mix.variable(system_mix.variable_number("aux_zc")));
    sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_fc")),
      system_mix.variable(system_mix.variable_number("aux_fc")));
    AutoPtr<NumericVector<Number> > just_aux = system_mix.solution->clone();
    sol_transfer.transfer(system_primary.variable(system_primary.variable_number("c")),
      system_mix.variable(system_mix.variable_number("c")));
    sol_transfer.transfer(system_primary.variable(system_primary.variable_number("zc")),
      system_mix.variable(system_mix.variable_number("zc")));
    sol_transfer.transfer(system_primary.variable(system_primary.variable_number("fc")),
      system_mix.variable(system_mix.variable_number("fc")));

    if(!splitSuperAdj){ //solve super-adjoint as single adjoint
      system_mix.assemble_qoi_sides = true; //QoI doesn't involve sides
      
      std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve start ~*~*~*~*~*~*~*~*~\n" << std::endl;
      std::pair<unsigned int, Real> adjsolve = system_mix.adjoint_solve();
      std::cout << "number of iterations to solve adjoint: " << adjsolve.first << std::endl;
      std::cout << "final residual of adjoint solve: " << adjsolve.second << std::endl;
      std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve end ~*~*~*~*~*~*~*~*~" << std::endl;
  
      NumericVector<Number> &dual_sol = system_mix.get_adjoint_solution(0); //DEBUG
      
      system_mix.assemble(); //calculate residual to correspond to solution
      
      //std::cout << "\n sadj norm: " << system_mix.calculate_norm(dual_sol, L2) << std::endl; //DEBUG
      //std::cout << system_mix.calculate_norm(dual_sol, 0, L2) << std::endl; //DEBUG
      //std::cout << system_mix.calculate_norm(dual_sol, 1, L2) << std::endl; //DEBUG
      //std::cout << system_mix.calculate_norm(dual_sol, 2, L2) << std::endl; //DEBUG
      //std::cout << system_mix.calculate_norm(dual_sol, 3, L2) << std::endl; //DEBUG
      //std::cout << system_mix.calculate_norm(dual_sol, 4, L2) << std::endl; //DEBUG
      //std::cout << system_mix.calculate_norm(dual_sol, 5, L2) << std::endl; //DEBUG
    }else{ //solve super-adjoint as
      system_mix.assemble(); //calculate residual to correspond to solution
      std::cout << "\n Begin primary super-adjoint solve...\n" << std::endl;
      system_sadj_primary.solve();
      std::cout << "\n End primary super-adjoint solve, begin auxiliary super-adjoint solve...\n" << std::endl;
      system_sadj_aux.solve();
      std::cout << "\n End auxiliary super-adjoint solve...\n" << std::endl;
      const std::string & adjoint_solution0_name = "adjoint_solution0";
      system_mix.add_vector(adjoint_solution0_name, false, GHOSTED);
      system_mix.set_vector_as_adjoint(adjoint_solution0_name,0);
      NumericVector<Number> &eep = system_mix.add_adjoint_rhs(0);
      system_mix.set_adjoint_already_solved(true);
      NumericVector<Number> &dual_sol = system_mix.get_adjoint_solution(0);
      NumericVector<Number> &primal_sol = *system_mix.solution;
      dual_sol.swap(primal_sol);
      sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_c")),
        system_mix.variable(system_mix.variable_number("aux_c")));
      sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_zc")),
        system_mix.variable(system_mix.variable_number("aux_zc")));
      sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_fc")),
        system_mix.variable(system_mix.variable_number("aux_fc")));
      sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_c")),
        system_mix.variable(system_mix.variable_number("c")));
      sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_zc")),
        system_mix.variable(system_mix.variable_number("zc")));
      sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_fc")),
        system_mix.variable(system_mix.variable_number("fc")));
      //std::cout << "\n sadj norm: " << system_mix.calculate_norm(primal_sol, L2) << std::endl; //DEBUG
      dual_sol.swap(primal_sol);
      //std::cout << "\n sadj norm: " << system_mix.calculate_norm(primal_sol, L2) << std::endl; //DEBUG
      //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 0, L2) << std::endl; //DEBUG
      //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 1, L2) << std::endl; //DEBUG
      //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 2, L2) << std::endl; //DEBUG
      //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 0, L2) << std::endl; //DEBUG
      //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 1, L2) << std::endl; //DEBUG
      //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 2, L2) << std::endl; //DEBUG
    }
    NumericVector<Number> &dual_solution = system_mix.get_adjoint_solution(0);
/*  
    NumericVector<Number> &primal_solution = *system_mix.solution; //DEBUG
    primal_solution.swap(dual_solution); //DEBUG
    ExodusII_IO(mesh).write_timestep("super_adjoint.exo",
                                   equation_systems,
                                   1, /  his number indicates how many time steps are being written to the file
                                   system_mix.time); //DEBUG
    primal_solution.swap(dual_solution); //DEBUG
*/
    //adjoint-weighted residual
    AutoPtr<NumericVector<Number> > adjresid = system_mix.solution->zero_clone();
    adjresid->pointwise_mult(*system_mix.rhs,dual_solution); 
    adjresid->scale(-0.5);
    std::cout << "\n -0.5*M'_HF(psiLF)(superadj): " << adjresid->sum() << std::endl; //DEBUG
    
    //LprimeHF(psiLF)
    AutoPtr<NumericVector<Number> > LprimeHF_psiLF = system_mix.solution->zero_clone();
    LprimeHF_psiLF->pointwise_mult(*system_mix.rhs,*just_aux);
    std::cout << " L'_HF(psiLF): " << LprimeHF_psiLF->sum() << std::endl; //DEBUG
    
    //QoI and error estimate
    std::cout << "QoI: " << std::setprecision(17) << system_primary.getQoI() << std::endl;
    std::cout << "QoI Error estimate: " << std::setprecision(17) 
        << adjresid->sum()+LprimeHF_psiLF->sum() << std::endl; 
        
    relError = fabs((adjresid->sum()+LprimeHF_psiLF->sum())/system_primary.getQoI());
    
    //print out information
    std::cout << "Estimated absolute relative qoi error: " << relError << std::endl << std::endl;
    std::cout << "Estimated HF QoI: " << std::setprecision(17) << system_primary.getQoI()+adjresid->sum()+LprimeHF_psiLF->sum() << std::endl;
    clock_t end = clock();
    std::cout << "Time so far: " << double(end-begin)/CLOCKS_PER_SEC << " seconds..." << std::endl;
    std::cout << "Time for inverse problem: " << double(end_inv-begin_inv)/CLOCKS_PER_SEC << " seconds..." << std::endl;
    std::cout << "Time for extra error estimate bits: " << double(end-begin_err_est)/CLOCKS_PER_SEC << " seconds..." << std::endl;
    std::cout << "    Time to get auxiliary problems: " << double(end_aux-begin_err_est)/CLOCKS_PER_SEC << " seconds..." << std::endl;
    std::cout << "    Time to get superadjoint: " << double(end-end_aux)/CLOCKS_PER_SEC << " seconds...\n" << std::endl;
    
    //proportion of domain refined at this iteration
    MeshBase::element_iterator       elem_it  = mesh.elements_begin();
    const MeshBase::element_iterator elem_end = mesh.elements_end();
    double numMarked = 0.;
    for (; elem_it != elem_end; ++elem_it){
      Elem* elem = *elem_it;
      numMarked += elem->subdomain_id();
    }
    std::cout << "Refinement fraction: " << numMarked/system_mix.get_mesh().n_elem() << std::endl << std::endl;

    
    //output at each iteration
    std::stringstream ss;
    ss << refIter;
    std::string str = ss.str();
    std::string write_error_basis_blame = 
      (infile("error_est_output_file_basis_blame", "error_est_breakdown_basis_blame")) + str + ".dat";
    std::ofstream output2(write_error_basis_blame);
    for(unsigned int i = 0 ; i < adjresid->size(); i++){
      if(output2.is_open())
        output2 << (*adjresid)(i) + (*LprimeHF_psiLF)(i) << "\n";
    }
    output2.close();
    
    if(refIter < maxIter && relError > qoiErrorTol){ //if further refinement needed
    
      //collapse error contributions into nodes
      std::vector<std::pair<Number,dof_id_type> > node_errs(round(system_mix.n_dofs()/6.));
      for(unsigned int node_num = 0; node_num < node_errs.size(); node_num++){
        node_errs[node_num] = std::pair<Number,dof_id_type>
                             (fabs((*adjresid)(6*node_num) + (*LprimeHF_psiLF)(6*node_num)
                            + (*adjresid)(6*node_num+1) + (*LprimeHF_psiLF)(6*node_num+1)
                            + (*adjresid)(6*node_num+2) + (*LprimeHF_psiLF)(6*node_num+2)
                            + (*adjresid)(6*node_num+3) + (*LprimeHF_psiLF)(6*node_num+3)
                            + (*adjresid)(6*node_num+4) + (*LprimeHF_psiLF)(6*node_num+4)
                            + (*adjresid)(6*node_num+5) + (*LprimeHF_psiLF)(6*node_num+5)), node_num);
      }
  
      //find nodes contributing the most
      //double refPcnt = std::min((refIter+1)*refStep,1.);
      double refPcnt = std::min(refStep,1.); //additional refinement (compared to previous iteration)
      int cutoffLoc = round(node_errs.size()*refPcnt);
      std::sort(node_errs.begin(), node_errs.end()); 
      std::reverse(node_errs.begin(), node_errs.end()); 
      
      //find elements in support of worst offenders
      std::vector<dof_id_type> markMe;
      markMe.reserve(cutoffLoc*8);
      for(int i = 0; i < cutoffLoc; i++){
        markMe.insert(markMe.end(), node_to_elem[node_errs[i].second].begin(), node_to_elem[node_errs[i].second].end());
      }
  
      //mark those elements for refinement.
      for(int i = 0; i < markMe.size(); i++){
        if(!avoid_sides || (avoid_sides && !mesh.elem(markMe[i])->on_boundary()))
          mesh.elem(markMe[i])->subdomain_id() = 1; //assuming HF regions marked with 1
      }
  
      //to test whether assignment matches matlab's
      /*std::string stash_assign = "divvy_c_poke.txt";
      std::ofstream output_dbg(stash_assign.c_str());
      MeshBase::element_iterator       elem_it  = mesh.elements_begin();
      const MeshBase::element_iterator elem_end = mesh.elements_end();
      for (; elem_it != elem_end; ++elem_it){
        Elem* elem = *elem_it;
            
        if(output_dbg.is_open()){
          output_dbg << elem->id() << " " << elem->subdomain_id() << "\n";
        }
      }
      output_dbg.close();*/
      
#ifdef LIBMESH_HAVE_EXODUS_API
    std::stringstream ss2;
    ss2 << refIter + 1;
    std::string str = ss2.str();
    std::string write_divvy = "divvy" + str + ".exo";
    ExodusII_IO (mesh).write_equation_systems(write_divvy,equation_systems); //DEBUG
#endif // #ifdef LIBMESH_HAVE_EXODUS_API
    }
    refIter += 1;
  }
  
  std::string stash_assign = "divvy_final.txt";
  std::ofstream output_dbg(stash_assign.c_str());
  MeshBase::element_iterator       elem_it  = mesh.elements_begin();
  const MeshBase::element_iterator elem_end = mesh.elements_end();
  double numMarked = 0.;
  for (; elem_it != elem_end; ++elem_it){
    Elem* elem = *elem_it;
    numMarked += elem->subdomain_id();
    if(output_dbg.is_open()){
      output_dbg << elem->id() << " " << elem->subdomain_id() << "\n";
    }
  }
  output_dbg.close();
  
  std::cout << "\nRefinement concluded..." << std::endl;
  std::cout << "Final refinement fraction: " << numMarked/system_mix.get_mesh().n_elem() << std::endl;
  std::cout << "Final estimated relative error: " << relError << std::endl;
  
  return 0; //done

} //end main