Hi,

I am solving the basic diffusion equation using the direct method (based on 
Step-52).

I have made the following changes from Step-52 tutorial

1. The domain is now 1D (as opposed to 2D in step-52)
2. We have Neumann BCs on both ends (left NeumannBC = 0.5, right NeumannBC= 
0)
3. Removes the code for MMS validation (i.e. no source term S(t)) so that 
we solve for the unknown field variable, instead of verifying whether the 
pre-formulated analytical solution is retrieved)
4. Sets the absorpotion coefficient, Sigma_a = 0
5. Sets a non-zero initial condition (but a spatially constant value).

The C++ source code & Cmakelists.txt files are attached herewith. The 
solution is indeed correct and is as expected, and I have visualised this 
in Paraview. However, I'd like to understand the compilation warnings. 

Some of them have to do with "unused variables", which are somewhat 
straightforward to get rid of.  But the other warnings which all have the 
string  "required from here" is not so clear to me. 

Can someone please explain what these warnings mean, and what is the best 
practice for refactoring it to avoid such warnings.

Thanks!
Krishna

-- 
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see 
https://groups.google.com/d/forum/dealii?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to dealii+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/dealii/d6aaa13b-5325-4f4a-9493-23859a5bcb9co%40googlegroups.com.
#include <deal.II/base/function.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/time_stepping.h>

#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_tools.h>

#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_values.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_out.h>
#include <deal.II/grid/tria.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>

#include <deal.II/lac/affine_constraints.h>
#include <deal.II/lac/sparse_direct.h>

#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/vector_tools.h>

#include <cmath>
#include <fstream>
#include <iostream>
#include <map>

namespace DiffusionEqn
{
  using namespace dealii;


  template <int dim>
  class SolidDiffusion
  {
  public:
    SolidDiffusion();

    void run();

  private:
    void setup_system();

    void assemble_system(); // Assembles all components of matrix i.e. those
    // multiplying U(t)

    // This gives the numerical value of the BC (at left boundary in 1D case)
    double get_boundary_neumann_value(const double time) const;

    // The 'evaluate_diffusion' function below evaluates RHS of weak form of
    // spatially discretised PDE (M^-1  (-Dy-Ay+S + 𝛽(t) 𝜓(0)) ). Do not forget
    // that this function's return value already accounts for M^-1.

    Vector<double> evaluate_diffusion(const double          time,
                                      const Vector<double> &y) const;

    void output_results(const double                     time,
                        const unsigned int               time_step,
                        TimeStepping::runge_kutta_method method) const;

    unsigned int
    embedded_explicit_method(const TimeStepping::runge_kutta_method method,
                             const unsigned int n_time_steps,
                             const double       initial_time,
                             const double       final_time);


    const unsigned int fe_degree;

    const double diffusion_coefficient;
    const double absorption_cross_section;

    Triangulation<dim> triangulation;

    const FE_Q<dim> fe;

    DoFHandler<dim> dof_handler;

    AffineConstraints<double> constraint_matrix;

    SparsityPattern sparsity_pattern;

    SparseMatrix<double> system_matrix; // - \mathcal{D} - \mathcal{A}
    SparseMatrix<double> mass_matrix;

    SparseDirectUMFPACK inverse_mass_matrix;

    Vector<double> solution;

    const double b; // length of the hypercube domain in each dimension
  };


  template <int dim>
  SolidDiffusion<dim>::SolidDiffusion()
    : fe_degree(3)
    , diffusion_coefficient(1. / 25.) // value of D
    // , diffusion_coefficient(1. / 30.) // value of D
    , absorption_cross_section(0.) // value of \Sigma_a
    , fe(fe_degree)
    , dof_handler(triangulation)
    , b(5.0)
  {}


  template <int dim>
  void SolidDiffusion<dim>::setup_system()
  {
    dof_handler.distribute_dofs(fe);

    constraint_matrix.close();

    DynamicSparsityPattern dsp(dof_handler.n_dofs());
    DoFTools::make_sparsity_pattern(dof_handler, dsp, constraint_matrix);
    sparsity_pattern.copy_from(dsp);

    system_matrix.reinit(sparsity_pattern);
    mass_matrix.reinit(sparsity_pattern);
    solution.reinit(dof_handler.n_dofs());
  }


  template <int dim>
  void SolidDiffusion<dim>::assemble_system() // Assembles all matrix components
  // i.e. those multiplying U(t)
  {
    system_matrix = 0.;
    mass_matrix   = 0.;

    const QGauss<dim> quadrature_formula(fe_degree + 1);

    FEValues<dim> fe_values(fe,
                            quadrature_formula,
                            update_values | update_gradients |
                              update_JxW_values);

    const unsigned int dofs_per_cell = fe.dofs_per_cell;
    const unsigned int n_q_points    = quadrature_formula.size();

    FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
    FullMatrix<double> cell_mass_matrix(dofs_per_cell, dofs_per_cell);

    std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);

    for (const auto &cell : dof_handler.active_cell_iterators())
      {
        cell_matrix      = 0.;
        cell_mass_matrix = 0.;

        fe_values.reinit(cell);

        for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
          for (unsigned int i = 0; i < dofs_per_cell; ++i)
            for (unsigned int j = 0; j < dofs_per_cell; ++j)
              {
                cell_matrix(i, j) +=
                  ((-diffusion_coefficient *                // (-D
                      fe_values.shape_grad(i, q_point) *    //  * ∇ phi_i
                      fe_values.shape_grad(j, q_point)      //  * ∇ phi_j
                    - absorption_cross_section *            //  -Sigma
                        fe_values.shape_value(i, q_point) * //  * phi_i
                        fe_values.shape_value(j, q_point))  //  * phi_j)
                   * fe_values.JxW(q_point));               // * dx
                cell_mass_matrix(i, j) += fe_values.shape_value(i, q_point) *
                                          fe_values.shape_value(j, q_point) *
                                          fe_values.JxW(q_point);
              }

        cell->get_dof_indices(local_dof_indices);

        constraint_matrix.distribute_local_to_global(cell_matrix,
                                                     local_dof_indices,
                                                     system_matrix);
        constraint_matrix.distribute_local_to_global(cell_mass_matrix,
                                                     local_dof_indices,
                                                     mass_matrix);
      }

    inverse_mass_matrix.initialize(mass_matrix);
  }

  template <int dim>
  double
  SolidDiffusion<dim>::get_boundary_neumann_value(const double time) const
  {
    return 0.5; // for now, hard-coding some neumannBC value
  }


  // Currently set up for only for 1D case. This is highly problem-specific
  template <int dim>
  class InitialValues : public Function<dim>
  {
  public:
    InitialValues(const unsigned int n_components = 1, const double time = 0.)
      : Function<dim>(n_components, time)
    {}
    virtual double value(const Point<dim> & p,
                         const unsigned int component = 0) const override
    {
      const double x         = p(0);
      const double b         = 5.0;
      const double amplitude = 1.0;

      // try various manually chosen spatial function(s) for the IC

      // Gaussian curve centred at half the domain
      // return amplitude * exp(-(8.0 * pow(x - 0.5 * b, 2) / b));

      // Gaussian curve centred at 1/3rd of the domain length
      // return amplitude * exp(-(2.0 * pow(x - 0.3 * b, 2) / b));

      // Spatially constant IC
      return amplitude;
    }
  };



  template <int dim>
  Vector<double>
  SolidDiffusion<dim>::evaluate_diffusion(const double          time,
                                          const Vector<double> &y) const
  {
    Vector<double> tmp(dof_handler.n_dofs());
    tmp = 0.;
    system_matrix.vmult(tmp, y); // tmp now has (-mathcal{D} - \mathcal{A}) * y

    const QGauss<dim> quadrature_formula(fe_degree + 1);

    FEValues<dim> fe_values(fe,
                            quadrature_formula,
                            update_values | update_quadrature_points |
                              update_JxW_values);

    const unsigned int n_q_points = quadrature_formula.size();

    const QGauss<dim - 1> face_quadrature_formula(fe.degree + 1);

    FEFaceValues<dim> fe_face_values(fe,
                                     face_quadrature_formula,
                                     update_values | update_JxW_values);

    const unsigned int n_face_q_points = face_quadrature_formula.size();

    const unsigned int dofs_per_cell = fe.dofs_per_cell;

    Vector<double> cell_neumannbc_contribution(dofs_per_cell);
    std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);

    for (const auto &cell : dof_handler.active_cell_iterators())
      {
        cell_neumannbc_contribution = 0.;
        for (unsigned int face_number = 0;
             face_number < GeometryInfo<dim>::faces_per_cell;
             ++face_number)
          if (cell->face(face_number)->at_boundary() &&
              (cell->face(face_number)->boundary_id() == 0))
            // In 1D, boundary_id of left edge is 0 and right edge is 1
            {
              fe_face_values.reinit(cell, face_number);
              for (unsigned int q_point = 0; q_point < n_face_q_points;
                   ++q_point)
                {
                  const double left_boundary_neumann_value =
                    get_boundary_neumann_value(time);
                  for (unsigned int i = 0; i < dofs_per_cell; ++i)
                    cell_neumannbc_contribution(i) +=
                      (left_boundary_neumann_value *            // \beta(t)
                       fe_face_values.shape_value(i, q_point) * // phi_i(x_q)
                       fe_face_values.JxW(q_point));            // dx
                }
            }

        cell->get_dof_indices(local_dof_indices);

        // tmp+=NeumannBC; i.e. (-D - A)y + NeumannBC
        constraint_matrix.distribute_local_to_global(
          cell_neumannbc_contribution, local_dof_indices, tmp);
      }


    Vector<double> value(dof_handler.n_dofs());
    inverse_mass_matrix.vmult(value, tmp);

    return value; // value contains -M^-1 * (-Dy - Ay + NeumannBC + optionally,
                  // S)
  }


  template <int dim>
  void SolidDiffusion<dim>::output_results(
    const double                     time,
    const unsigned int               time_step,
    TimeStepping::runge_kutta_method method) const
  {
    std::string method_name;

    switch (method)
      {
          case TimeStepping::DOPRI: {
            method_name = "dopri";
            break;
          }
          default: {
            std::cout
              << "This time-stepping method is not implemented. Exiting ..."
              << std::endl;
            break;
          }
      }

    DataOut<dim> data_out;

    data_out.attach_dof_handler(dof_handler);
    data_out.add_data_vector(solution, "solution");

    data_out.build_patches();

    data_out.set_flags(DataOutBase::VtkFlags(time, time_step));

    const std::string filename = "solution_" + method_name + "-" +
                                 Utilities::int_to_string(time_step, 3) +
                                 ".vtu";
    std::ofstream output(filename);
    data_out.write_vtu(output);

    static std::vector<std::pair<double, std::string>> times_and_names;

    static std::string method_name_prev = "";
    static std::string pvd_filename;
    if (method_name_prev != method_name)
      {
        times_and_names.clear();
        method_name_prev = method_name;
        pvd_filename     = "solution_" + method_name + ".pvd";
      }
    times_and_names.emplace_back(time, filename);
    std::ofstream pvd_output(pvd_filename);
    DataOutBase::write_pvd_record(pvd_output, times_and_names);
  }


  template <int dim>
  unsigned int SolidDiffusion<dim>::embedded_explicit_method(
    const TimeStepping::runge_kutta_method method,
    const unsigned int                     n_time_steps,
    const double                           initial_time,
    const double                           final_time)
  {
    double time_step =
      (final_time - initial_time) / static_cast<double>(n_time_steps);
    double       time          = initial_time;
    const double coarsen_param = 1.2;
    const double refine_param  = 0.8;
    const double min_delta     = 1e-8;
    const double max_delta     = 10 * time_step;
    const double refine_tol    = 1e-1;
    const double coarsen_tol   = 1e-5;


    constraint_matrix.distribute(solution);

    TimeStepping::EmbeddedExplicitRungeKutta<Vector<double>>
      embedded_explicit_runge_kutta(method,
                                    coarsen_param,
                                    refine_param,
                                    min_delta,
                                    max_delta,
                                    refine_tol,
                                    coarsen_tol);
    output_results(time, 0, method);

    unsigned int n_steps = 0;
    while (time < final_time)
      {
        if (time + time_step > final_time)
          time_step = final_time - time;

        time = embedded_explicit_runge_kutta.evolve_one_time_step(
          [this](const double time, const Vector<double> &y) {
            return this->evaluate_diffusion(time, y);
          },
          time,
          time_step,
          solution);

        constraint_matrix.distribute(solution);

        if ((n_steps + 1) % 10 == 0)
          output_results(time, n_steps + 1, method);

        time_step = embedded_explicit_runge_kutta.get_status().delta_t_guess;
        ++n_steps;
      }

    return n_steps;
  }


  template <int dim>
  void SolidDiffusion<dim>::run()
  {
    GridGenerator::hyper_cube(triangulation, 0., b); // b = 5 for now
    triangulation.refine_global(6);

    setup_system();

    VectorTools::project(dof_handler,
                         constraint_matrix,
                         QGauss<dim>(fe.degree + 1),
                         // InitialValues<1>(1, time),
                         InitialValues<dim>(1, 0),
                         solution);


    assemble_system(); // Assembles matrix components (those multiplying U(t))

    unsigned int       n_steps      = 0;
    const unsigned int n_time_steps = 200;
    const double       initial_time = 0.;
    const double       final_time   = 10.;

    n_steps = embedded_explicit_method(TimeStepping::DOPRI,
                                       n_time_steps,
                                       initial_time,
                                       final_time);
  }
} // namespace DiffusionEqn



int main()
{
  try
    {
      using namespace dealii;
      using namespace DiffusionEqn;
      SolidDiffusion<1> soliddiffusion;
      soliddiffusion.run();
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl
                << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Exception on processing: " << std::endl
                << exc.what() << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl
                << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Unknown exception!" << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    };

  return 0;
}
##
#  CMake script for the solid_diffusion program:
##

# Set the name of the project and target:
SET(PROJECT_NAME "solid_diffusion")
# SET(TARGET "solid_diffusion")
SET(TARGET ${PROJECT_NAME}.run)

SET(TARGET_SRC
    ${PROJECT_NAME}.cc
  )

# Define the output that should be cleaned:
SET(CLEAN_UP_FILES *.vtu *.pvd)

# Usually, you will not need to modify anything beyond this point...

CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)

FIND_PACKAGE(deal.II 9.2.0 QUIET
  HINTS ${deal.II_DIR} ${DEAL_II_DIR} ../ ../../ $ENV{DEAL_II_DIR}
  )
IF(NOT ${deal.II_FOUND})
  MESSAGE(FATAL_ERROR "\n"
    "*** Could not locate a (sufficiently recent) version of deal.II. ***\n\n"
    "You may want to either pass a flag -DDEAL_II_DIR=/path/to/deal.II to 
cmake\n"
    "or set an environment variable \"DEAL_II_DIR\" that contains this path."
    )
ENDIF()

DEAL_II_INITIALIZE_CACHED_VARIABLES()
PROJECT(${TARGET})
DEAL_II_INVOKE_AUTOPILOT()
##
#  CMake script for the solid_diffusion program:
##

# Set the name of the project and target:
SET(PROJECT_NAME "solid_diffusion")
# SET(TARGET "solid_diffusion")
SET(TARGET ${PROJECT_NAME}.run)

SET(TARGET_SRC
    ${PROJECT_NAME}.cc
  )

# Define the output that should be cleaned:
SET(CLEAN_UP_FILES *.vtu *.pvd)

# Usually, you will not need to modify anything beyond this point...

CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)

FIND_PACKAGE(deal.II 9.2.0 QUIET
  HINTS ${deal.II_DIR} ${DEAL_II_DIR} ../ ../../ $ENV{DEAL_II_DIR}
  )
IF(NOT ${deal.II_FOUND})
  MESSAGE(FATAL_ERROR "\n"
    "*** Could not locate a (sufficiently recent) version of deal.II. ***\n\n"
    "You may want to either pass a flag -DDEAL_II_DIR=/path/to/deal.II to 
cmake\n"
    "or set an environment variable \"DEAL_II_DIR\" that contains this path."
    )
ENDIF()

DEAL_II_INITIALIZE_CACHED_VARIABLES()
PROJECT(${TARGET})
DEAL_II_INVOKE_AUTOPILOT()

-- 
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see 
https://groups.google.com/d/forum/dealii?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to dealii+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/dealii/d6aaa13b-5325-4f4a-9493-23859a5bcb9co%40googlegroups.com.

Reply via email to