Beispiel #1
0
// The main program
int main(int argc, char** argv)
{
    // Initialize libMesh
    LibMeshInit init(argc, argv);

    // Parameters
    GetPot infile("fem_system_params.in");
    const Real global_tolerance          = infile("global_tolerance", 0.);
    const unsigned int nelem_target      = infile("n_elements", 400);
    const bool transient                 = infile("transient", true);
    const Real deltat                    = infile("deltat", 0.005);
    unsigned int n_timesteps             = infile("n_timesteps", 1);
    //const unsigned int coarsegridsize    = infile("coarsegridsize", 1);
    const unsigned int coarserefinements = infile("coarserefinements", 0);
    const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10);
    //const unsigned int dim               = 2;

#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());
    GetPot infileForMesh("convdiff_mprime.in");
    std::string find_mesh_here = infileForMesh("mesh","psiLF_mesh.xda");
    mesh.read(find_mesh_here);

    std::cout << "Read in mesh from: " << find_mesh_here << "\n\n";

    // And an object to refine it
    MeshRefinement mesh_refinement(mesh);
    mesh_refinement.coarsen_by_parents() = true;
    mesh_refinement.absolute_global_tolerance() = global_tolerance;
    mesh_refinement.nelem_target() = nelem_target;
    mesh_refinement.refine_fraction() = 0.3;
    mesh_refinement.coarsen_fraction() = 0.3;
    mesh_refinement.coarsen_threshold() = 0.1;

    //mesh_refinement.uniformly_refine(coarserefinements);

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

    // Create an equation systems object.
    EquationSystems equation_systems (mesh);

    // Name system
    ConvDiff_MprimeSys & system =
        equation_systems.add_system<ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys");

    // Steady-state problem
    system.time_solver =
        AutoPtr<TimeSolver>(new SteadySolver(system));

    // Sanity check that we are indeed solving a steady problem
    libmesh_assert_equal_to (n_timesteps, 1);

    // Read in all the equation systems data from the LF solve (system, solutions, rhs, etc)
    std::string find_psiLF_here = infileForMesh("psiLF_file","psiLF.xda");
    std::cout << "Looking for psiLF at: " << find_psiLF_here << "\n\n";

    equation_systems.read(find_psiLF_here, READ,
                          EquationSystems::READ_HEADER |
                          EquationSystems::READ_DATA |
                          EquationSystems::READ_ADDITIONAL_DATA);

    // Check that the norm of the solution read in is what we expect it to be
    Real readin_L2 = system.calculate_norm(*system.solution, 0, L2);
    std::cout << "Read in solution norm: "<< readin_L2 << std::endl << std::endl;

    //DEBUG
    //equation_systems.write("right_back_out.xda", WRITE, EquationSystems::WRITE_DATA |
    //		 EquationSystems::WRITE_ADDITIONAL_DATA);
#ifdef LIBMESH_HAVE_GMV
    //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("right_back_out.gmv"), equation_systems);
#endif

    // Initialize the system
    //equation_systems.init ();  //already initialized by read-in

    // 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", 50000);
    solver->initial_linear_tolerance =
        infile("initial_linear_tolerance", 1.e-3);

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

    // Now we begin the timestep loop to compute the time-accurate
    // solution of the equations...not that this is transient, but eh, why not...
    for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
    {
        // A pretty update message
        std::cout << "\n\nSolving time step " << t_step << ", time = "
                  << system.time << std::endl;

        // Adaptively solve the timestep
        unsigned int a_step = 0;
        for (; a_step != max_adaptivesteps; ++a_step)
        {   // VESTIGIAL for now ('vestigial' eh ? ;) )

            std::cout << "\n\n I should be skipped what are you doing here lalalalalalala *!**!*!*!*!*!* \n\n";

            system.solve();
            system.postprocess();
            ErrorVector error;
            AutoPtr<ErrorEstimator> error_estimator;

            // To solve to a tolerance in this problem we
            // need a better estimator than Kelly
            if (global_tolerance != 0.)
            {
                // We can't adapt to both a tolerance and a mesh
                // size at once
                libmesh_assert_equal_to (nelem_target, 0);

                UniformRefinementEstimator *u =
                    new UniformRefinementEstimator;

                // The lid-driven cavity problem isn't in H1, so
                // lets estimate L2 error
                u->error_norm = L2;

                error_estimator.reset(u);
            }
            else
            {
                // If we aren't adapting to a tolerance we need a
                // target mesh size
                libmesh_assert_greater (nelem_target, 0);

                // Kelly is a lousy estimator to use for a problem
                // not in H1 - if we were doing more than a few
                // timesteps we'd need to turn off or limit the
                // maximum level of our adaptivity eventually
                error_estimator.reset(new KellyErrorEstimator);
            }

            // Calculate error
            std::vector<Real> weights(9,1.0);  // based on u, v, p, c, their adjoints, and source parameter

            // Keep the same default norm type.
            std::vector<FEMNormType>
            norms(1, error_estimator->error_norm.type(0));
            error_estimator->error_norm = SystemNorm(norms, weights);

            error_estimator->estimate_error(system, error);

            // Print out status at each adaptive step.
            Real global_error = error.l2_norm();
            std::cout << "Adaptive step " << a_step << ": " << std::endl;
            if (global_tolerance != 0.)
                std::cout << "Global_error = " << global_error
                          << std::endl;
            if (global_tolerance != 0.)
                std::cout << "Worst element error = " << error.maximum()
                          << ", mean = " << error.mean() << std::endl;

            if (global_tolerance != 0.)
            {
                // If we've reached our desired tolerance, we
                // don't need any more adaptive steps
                if (global_error < global_tolerance)
                    break;
                mesh_refinement.flag_elements_by_error_tolerance(error);
            }
            else
            {
                // If flag_elements_by_nelem_target returns true, this
                // should be our last adaptive step.
                if (mesh_refinement.flag_elements_by_nelem_target(error))
                {
                    mesh_refinement.refine_and_coarsen_elements();
                    equation_systems.reinit();
                    a_step = max_adaptivesteps;
                    break;
                }
            }

            // Carry out the adaptive mesh refinement/coarsening
            mesh_refinement.refine_and_coarsen_elements();
            equation_systems.reinit();

            std::cout << "Refined mesh to "
                      << mesh.n_active_elem()
                      << " active elements and "
                      << equation_systems.n_active_dofs()
                      << " active dofs." << std::endl;
        } // End loop over adaptive steps

        // Do one last solve if necessary
        if (a_step == max_adaptivesteps)
        {
            QoISet qois;
            std::vector<unsigned int> qoi_indices;

            qoi_indices.push_back(0);
            qois.add_indices(qoi_indices);

            qois.set_weight(0, 1.0);

            system.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.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_solution = system.get_adjoint_solution(0);
            NumericVector<Number> &primal_solution = *system.solution;

            primal_solution.swap(dual_solution);
            ExodusII_IO(mesh).write_timestep("super_adjoint.exo",
                                             equation_systems,
                                             1, /* This number indicates how many time steps
	                                       are being written to the file */
                                             system.time);
            primal_solution.swap(dual_solution);

            system.assemble(); //overwrite residual read in from psiLF solve

            // The total error estimate
            system.postprocess(); //to compute M_HF(psiLF) and M_LF(psiLF) terms
            Real QoI_error_estimate = (-0.5*(system.rhs)->dot(dual_solution)) + system.get_MHF_psiLF() - system.get_MLF_psiLF();
            std::cout << "\n\n 0.5*M'_HF(psiLF)(superadj): " << std::setprecision(17) << 0.5*(system.rhs)->dot(dual_solution) << "\n";
            std::cout << " M_HF(psiLF): " << std::setprecision(17) << system.get_MHF_psiLF() << "\n";
            std::cout << " M_LF(psiLF): " << std::setprecision(17) << system.get_MLF_psiLF() << "\n";
            std::cout << "\n\n Residual L2 norm: " << system.calculate_norm(*system.rhs, L2) << "\n";
            std::cout << " Residual discrete L2 norm: " << system.calculate_norm(*system.rhs, DISCRETE_L2) << "\n";
            std::cout << " Super-adjoint L2 norm: " << system.calculate_norm(dual_solution, L2) << "\n";
            std::cout << " Super-adjoint discrete L2 norm: " << system.calculate_norm(dual_solution, DISCRETE_L2) << "\n";
            std::cout << "\n\n QoI error estimate: " << std::setprecision(17) << QoI_error_estimate << "\n\n";

            //DEBUG
            std::cout << "\n------------ herp derp ------------" << std::endl;
            //libMesh::out.precision(16);
            //dual_solution.print();
            //system.get_adjoint_rhs().print();

            AutoPtr<NumericVector<Number> > adjresid = system.solution->clone();
            (system.matrix)->vector_mult(*adjresid,system.get_adjoint_solution(0));
            SparseMatrix<Number>& adjmat = *system.matrix;
            (system.matrix)->get_transpose(adjmat);
            adjmat.vector_mult(*adjresid,system.get_adjoint_solution(0));
            //std::cout << "******************** matrix-superadj product (libmesh) ************************" << std::endl;
            //adjresid->print();
            adjresid->add(-1.0, system.get_adjoint_rhs(0));
            //std::cout << "******************** superadjoint system residual (libmesh) ***********************" << std::endl;
            //adjresid->print();
            std::cout << "\n\nadjoint system residual (discrete L2): " << system.calculate_norm(*adjresid,DISCRETE_L2) << std::endl;
            std::cout << "adjoint system residual (L2, all): " << system.calculate_norm(*adjresid,L2) << std::endl;
            std::cout << "adjoint system residual (L2, 0): " << system.calculate_norm(*adjresid,0,L2) << std::endl;
            std::cout << "adjoint system residual (L2, 1): " << system.calculate_norm(*adjresid,1,L2) << std::endl;
            std::cout << "adjoint system residual (L2, 2): " << system.calculate_norm(*adjresid,2,L2) << std::endl;
            std::cout << "adjoint system residual (L2, 3): " << system.calculate_norm(*adjresid,3,L2) << std::endl;
            std::cout << "adjoint system residual (L2, 4): " << system.calculate_norm(*adjresid,4,L2) << std::endl;
            std::cout << "adjoint system residual (L2, 5): " << system.calculate_norm(*adjresid,5,L2) << std::endl;
            /*
            	AutoPtr<NumericVector<Number> > sadj_matlab = system.solution->clone();
            	AutoPtr<NumericVector<Number> > adjresid_matlab = system.solution->clone();
            	if(FILE *fp=fopen("superadj_matlab.txt","r")){
              	Real value;
              	int counter = 0;
              	int flag = 1;
              	while(flag != -1){
              		flag = fscanf(fp,"%lf",&value);
              		if(flag != -1){
            				sadj_matlab->set(counter, value);
            				counter += 1;
              		}
              	}
              	fclose(fp);
            	}
            	(system.matrix)->vector_mult(*adjresid_matlab,*sadj_matlab);
            	//std::cout << "******************** matrix-superadj product (matlab) ***********************" << std::endl;
            	//adjresid_matlab->print();
            	adjresid_matlab->add(-1.0, system.get_adjoint_rhs(0));
            	//std::cout << "******************** superadjoint system residual (matlab) ***********************" << std::endl;
            	//adjresid_matlab->print();
            	std::cout << "\n\nmatlab import adjoint system residual (discrete L2): " << system.calculate_norm(*adjresid_matlab,DISCRETE_L2) << "\n" << std::endl;
            */
            /*
            	AutoPtr<NumericVector<Number> > sadj_fwd_hack = system.solution->clone();
            	AutoPtr<NumericVector<Number> > adjresid_fwd_hack = system.solution->clone();
            	if(FILE *fp=fopen("superadj_forward_hack.txt","r")){
              	Real value;
              	int counter = 0;
              	int flag = 1;
              	while(flag != -1){
              		flag = fscanf(fp,"%lf",&value);
              		if(flag != -1){
            				sadj_fwd_hack->set(counter, value);
            				counter += 1;
              		}
              	}
              	fclose(fp);
            	}
            	(system.matrix)->vector_mult(*adjresid_fwd_hack,*sadj_fwd_hack);
            	//std::cout << "******************** matrix-superadj product (fwd_hack) ***********************" << std::endl;
            	//adjresid_fwd_hack->print();
            	adjresid_fwd_hack->add(-1.0, system.get_adjoint_rhs(0));
            	//std::cout << "******************** superadjoint system residual (fwd_hack) ***********************" << std::endl;
            	//adjresid_fwd_hack->print();
            	std::cout << "\n\nfwd_hack import adjoint system residual (discrete L2): " << system.calculate_norm(*adjresid_fwd_hack,DISCRETE_L2) << "\n" << std::endl;
            	std::cout << "fwd_hack adjoint system residual (L2, 0): " << system.calculate_norm(*adjresid_fwd_hack,0,L2) << std::endl;
            	std::cout << "fwd_hack adjoint system residual (L2, 1): " << system.calculate_norm(*adjresid_fwd_hack,1,L2) << std::endl;
            	std::cout << "fwd_hack adjoint system residual (L2, 2): " << system.calculate_norm(*adjresid_fwd_hack,2,L2) << std::endl;
            	std::cout << "fwd_hack adjoint system residual (L2, 3): " << system.calculate_norm(*adjresid_fwd_hack,3,L2) << std::endl;
            	std::cout << "fwd_hack adjoint system residual (L2, 4): " << system.calculate_norm(*adjresid_fwd_hack,4,L2) << std::endl;
            	std::cout << "fwd_hack adjoint system residual (L2, 5): " << system.calculate_norm(*adjresid_fwd_hack,5,L2) << std::endl;
            */
            //std::cout << "************************ system.matrix ***********************" << std::endl;
            //system.matrix->print();

            std::cout << "\n------------ herp derp ------------" << std::endl;

            // The cell wise breakdown
            ErrorVector cell_wise_error;
            cell_wise_error.resize((system.rhs)->size());
            for(unsigned int i = 0; i < (system.rhs)->size() ; i++)
            {
                if(i < system.get_mesh().n_elem())
                    cell_wise_error[i] = fabs(-0.5*((system.rhs)->el(i) * dual_solution(i))
                                              + system.get_MHF_psiLF(i) - system.get_MLF_psiLF(i));
                else
                    cell_wise_error[i] = fabs(-0.5*((system.rhs)->el(i) * dual_solution(i)));

                /*csv from 'save data' from gmv output gives a few values at each node point (value
                for every element that shares that node), yet paraview display only seems to show one
                of them -> the value in an element is given at each of the nodes that it has, hence the
                repetition; what is displayed in paraview is each element's value; even though MHF_psiLF
                and MLF_psiLF are stored by element this seems to give elemental contributions that
                agree with if we had taken the superadj-residual dot product by integrating over elements*/

                /*at higher mesh resolutions and lower k, weird-looking artifacts start to appear and
                it no longer agrees with output from manual integration of superadj-residual...*/
            }
            // Plot it
            std::ostringstream error_gmv;
            error_gmv << "error.gmv";
            cell_wise_error.plot_error(error_gmv.str(), equation_systems.get_mesh());

            //alternate element-wise breakdown, outputed as values matched to element centroids; for matlab plotz
            primal_solution.swap(dual_solution);
            system.postprocess(1);
            primal_solution.swap(dual_solution);
            system.postprocess(2);
            std::cout << "\n\n -0.5*M'_HF(psiLF)(superadj): " << std::setprecision(17) << system.get_half_adj_weighted_resid() << "\n";
            primal_solution.swap(dual_solution);

            std::string write_error_here = infileForMesh("error_est_output_file", "error_est_breakdown.dat");
            std::ofstream output(write_error_here);
            for(unsigned int i = 0 ; i < system.get_mesh().n_elem(); i++) {
                Point elem_cent = system.get_mesh().elem(i)->centroid();
                if(output.is_open()) {
                    output << elem_cent(0) << " " << elem_cent(1) << " "
                           << fabs(system.get_half_adj_weighted_resid(i) + system.get_MHF_psiLF(i) - system.get_MLF_psiLF(i)) << "\n";
                }
            }
            output.close();

        } // End if at max adaptive steps

#ifdef LIBMESH_HAVE_EXODUS_API
        // Write out this timestep if we're requested to
        if ((t_step+1)%write_interval == 0)
        {
            std::ostringstream file_name;
            /*
                // We write the file in the ExodusII format.
                file_name << "out_"
                          << std::setw(3)
                          << std::setfill('0')
                          << std::right
                          << t_step+1
                          << ".e";
            			//this should write out the primal which should be the same as what's read in...
            			ExodusII_IO(mesh).write_timestep(file_name.str(),
            							                        equation_systems,
            							                        1, //number of time steps written to file
            							                        system.time);
            */
        }
#endif // #ifdef LIBMESH_HAVE_EXODUS_API
    }

    // All done.
    return 0;

} //end main
Beispiel #2
0
// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

  // This example requires a linear solver package.
  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
                           "--enable-petsc, --enable-trilinos, or --enable-eigen");

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

  // This doesn't converge with Eigen BICGSTAB for some reason...
  libmesh_example_requires(libMesh::default_solver_package() != EIGEN_SOLVERS, "--enable-petsc");

  libMesh::out << "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(init.comm());
  param.read(infile);

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

  // 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
  std::unique_ptr<MeshRefinement> mesh_refinement =
    build_mesh_refinement(mesh, param);

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

  libMesh::out << "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);

  libMesh::out << "Building system" << std::endl;

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

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

  libMesh::out << "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", param);

        // 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 unnecessarily 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", param);

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

        // Swap back again
        primal_solution.swap(dual_solution_1);

        libMesh::out << "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
        libMesh::out << "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);

        libMesh::out << "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;

        libMesh::out << "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
        std::unique_ptr<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
        libMesh::out << "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;

        libMesh::out << "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 effectivity indices (estimated error/true error)
        libMesh::out << "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;

        libMesh::out << "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;

        // For refinement purposes we need to sort by error
        // *magnitudes*, but AdjointRefinement gives us signed errors.
        if (!param.refine_uniformly)
          for (std::size_t i=0; i<QoI_elementwise_error.size(); i++)
            if (QoI_elementwise_error[i] != 0.)
              QoI_elementwise_error[i] = std::abs(QoI_elementwise_error[i]);

        // 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)
              {
                libMesh::out << "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();

        libMesh::out << "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", param);

        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 unnecessarily 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", param);

        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", param);

        primal_solution.swap(dual_solution_1);

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

        libMesh::out << "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);

        libMesh::out << "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;

        libMesh::out << "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
        std::unique_ptr<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
        libMesh::out << "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;

        libMesh::out << "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 effectivity indices (estimated error/true error)
        libMesh::out << "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;

        libMesh::out << "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;

        // Hard coded assert to ensure that the actual numbers we are getting are what they should be

        // The effectivity index isn't exactly reproducible at single precision
        // libmesh_assert_less(std::abs(std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) / std::abs(QoI_0_computed - QoI_0_exact) - 0.84010976704434637), 1.e-5);
        // libmesh_assert_less(std::abs(std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) / std::abs(QoI_1_computed - QoI_1_exact) - 0.48294428289950514), 1.e-5);

        // But the effectivity indices should always be sane
        libmesh_assert_less(std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) / std::abs(QoI_0_computed - QoI_0_exact), 2.5);
        libmesh_assert_greater(std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(0)) / std::abs(QoI_0_computed - QoI_0_exact), .4);
        libmesh_assert_less(std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) / std::abs(QoI_1_computed - QoI_1_exact), 2.5);
        libmesh_assert_greater(std::abs(adjoint_refinement_error_estimator->get_global_QoI_error_estimate(1)) / std::abs(QoI_1_computed - QoI_1_exact), .4);

        // And the computed errors should still be low
        libmesh_assert_less(std::abs(QoI_0_computed - QoI_0_exact), 2e-4);
        libmesh_assert_less(std::abs(QoI_1_computed - QoI_1_exact), 2e-4);
      }
  }

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

#endif // #ifndef LIBMESH_ENABLE_AMR

  // All done.
  return 0;
}
Beispiel #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_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;
}
Beispiel #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_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;
}
Beispiel #5
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 << '[' << 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);

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

  // 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 << "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;

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

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

#endif // #ifndef LIBMESH_ENABLE_AMR

  // All done.
  return 0;
}