Dear Wolfgang,
yes the mesh is quite coarse, but I want to investigate the functionality 
of how deal.ii outputs stresses and how these stresses are then displayed 
via for instance paraview. To really see the effects I intentionally use 
the coarse mesh.
So far, I actually do create a (derived) DataPostprocessor-Object (see the 
thinned out and altered step-8 tutorial attached to this message) similar 
to the procedure in step-32. You wrote, that the gradients are computed at 
the vertices. How so? If I look at line 291 of my code or at step-32, there 
is a loop over all quadrature points (  for (unsigned int q = 0; q < 
n_quadrature_points; ++q) ) which gets called for every cell. In the scope 
of this loop the shape function gradients at the quadrature points are used 
to compute the desired output variable by a special calculation rule. 
However, these are not the vertices. If the gradients are somehow again 
computed at the vertices, which might be an internal procedure of the 
DataPostprocessor-functionality of dealii, how would this procedure know 
what the special calculation rule of the desired output would look like?

Concerning your second note, thanks for pointing me in the direction of  
the Zienkiewicz-Zhu recovery procedure. The procedure is straightforward to 
me, however its implementation in deal.ii not (yet). There are some 
functions like the VectorTools::project() function, which is supposed to 
give a L2-projections. 
However, I am not quite sure how to use them. Therefore I tried to 
implement the  Zienkiewicz-Zhu recovery procedure myself. But there is a 
fundamental problem I could not solve so far. In elasticity problems for 2D 
or 3D we have a vector-valued solution. Therefore, in 2D for a 
triangulation with n Nodes we have 2n DoFs. If I want to add the projected 
scalar function (e.g. the mises stress) in form of a command like

data_out.add_data_vector(mises_stress_recovery, "mises_recovery");

to the output, there is the problem that the mises_stress_recovery vector 
only has a dimension of n, where as data_out wants a vector of dimension 
2n. How to deal with that issue?
I tried to generate a new dof_handler via 
DoFHandler<dim> dof_handler_recovery(this->triangulation);
FESystem<dim> fe_recovery(FE_Q<dim>(this->fe_degree),1); // here dim=1 
since we only have on dof per node
MappingQ<dim> mapping_recovery(this->fe_degree);
AffineConstraints<double> constraints_recovery;
dof_handler_recovery.distribute_dofs(fe_recovery);

and then assemble a mass matrix and a rhs to solve for the 
mises_stress_recovery vector. However, when looping over the cells, I am 
not sure how to reference to the cells. Should I use the cells of the newly 
created DoFHandler via 
for (const auto &cell : dof_handler_recovery.active_cell_iterators())
or via the DoFHandler of the original problem solution via
for (const auto &cell : dof_handler.active_cell_iterators()).

Do I really have to create a new DoFHandler? If not, how would one assemble 
the mass matrix, since for that we need the an local_dof_indices object 
like std::vector<types::global_dof_index> that points only to every second 
dof index or so.
I would be grateful for some tips or directions.

Best 
Konrad

-- 
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/c711eb18-b84b-4120-a46e-5bfc76773ec0n%40googlegroups.com.
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/tensor.h>
 
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/precondition.h>
#include <deal.II/lac/affine_constraints.h>
 
#include <deal.II/grid/tria.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_refinement.h>
#include <deal.II/grid/grid_out.h>

#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_tools.h>
 
#include <deal.II/fe/fe_values.h>
 
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/matrix_tools.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/lac/sparse_direct.h>
 
#include <deal.II/fe/fe_system.h>
#include <deal.II/fe/fe_q.h>
 
#include <fstream>
#include <iostream>

double TOL = 10E-9;
namespace Step8{
using namespace dealii;
  
template <int dim>
class ElasticProblem{
  public:
    ElasticProblem();
    void run();
  
  private:
    double E=10000.,nu=0.3;
    void setup_system();
    void assemble_system();
    void solve();
    void output_results() const;
    Triangulation<dim> triangulation;
    DoFHandler<dim>    dof_handler;
    FESystem<dim> fe;
    AffineConstraints<double> constraints;
    SparsityPattern      sparsity_pattern;
    SparseMatrix<double> system_matrix;
    Vector<double> solution;
    Vector<double> system_rhs;
};
 
template <int dim>
void right_hand_side(const std::vector<Point<dim>> &points,std::vector<Tensor<1, dim>> &  values){
  AssertDimension(values.size(), points.size());
  Assert(dim >= 2, ExcNotImplemented());
  Point<dim> point_1, point_2;
  point_1(0) = 0.5;
  point_2(0) = -0.5;
  for (unsigned int point_n = 0; point_n < points.size(); ++point_n)
    {
      if (((points[point_n] - point_1).norm_square() < 0.2 * 0.2) ||
          ((points[point_n] - point_2).norm_square() < 0.2 * 0.2))
        values[point_n][0] = 1.0;
      else
        values[point_n][0] = 0.0;

      if (points[point_n].norm_square() < 0.2 * 0.2)
        values[point_n][1] = 1.0;
      else
        values[point_n][1] = 0.0;
    }
}

template <int dim>
ElasticProblem<dim>::ElasticProblem()
  : dof_handler(triangulation)
  , fe(FE_Q<dim>(1), dim)
{}
 
template <int dim>
void ElasticProblem<dim>::setup_system(){
  dof_handler.distribute_dofs(fe);
  solution.reinit(dof_handler.n_dofs());
  system_rhs.reinit(dof_handler.n_dofs());
  constraints.clear();

	for (const auto &cell : triangulation.active_cell_iterators()){
		for (const auto &face : cell->face_iterators()){
			if (face->at_boundary()){
				if      (std::fabs(face->center()[0] + 0.5) < TOL)
					face->set_boundary_id(100);
				else if (std::fabs(face->center()[1] + 0.5) < TOL)
					face->set_boundary_id(101);
				else if (std::fabs(face->center()[0] - 0.5) < TOL)
					face->set_boundary_id(103);
				else if (std::fabs(face->center()[1] - 0.5) < TOL)
					face->set_boundary_id(104);
				else
					face->set_boundary_id(10);
			}
		}
	}

	VectorTools::interpolate_boundary_values( dof_handler,						// DOF handler object
                                            100,								// boundary id
                                            Functions::ZeroFunction<dim>(dim), // homogeneous boundary values
                                            constraints,						// constraint object to be modified
                                            ComponentMask(std::vector<bool>{true, false}));
	VectorTools::interpolate_boundary_values( dof_handler,
                                            101,
                                            Functions::ZeroFunction<dim>(dim), 
                                            constraints,						
                                            ComponentMask(std::vector<bool>{false, true}));
	VectorTools::interpolate_boundary_values( dof_handler,
                                            103,
                                            Functions::ConstantFunction<dim>(std::vector<double>{0.5, 0.0}), // pull boundary values
                                            constraints,
                                            ComponentMask(std::vector<bool>{true, false}));
  constraints.close();

  DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs());
  DoFTools::make_sparsity_pattern(dof_handler,
                                  dsp,
                                  constraints,
                                  /*keep_constrained_dofs = */ false);
  sparsity_pattern.copy_from(dsp);
  system_matrix.reinit(sparsity_pattern);
}

template <int dim>
SymmetricTensor<4, dim>
get_stress_strain_tensor(const double E, const double nu){
	const double lambda = (E*nu)/((1.+nu)*(1.-2.*nu));
	const double mu     = E/(2.*(1.+nu));
	SymmetricTensor<4, dim> C;
	for (unsigned int i = 0; i < dim; ++i)
		for (unsigned int j = 0; j < dim; ++j)
			for (unsigned int k = 0; k < dim; ++k)
				for (unsigned int l = 0; l < dim; ++l)
					C[i][j][k][l] = ( ((i == k) && (j == l) ? mu : 0.0) +
							              ((i == l) && (j == k) ? mu : 0.0) +
									          ((i == j) && (k == l) ? lambda : 0.0)); // ? returns value on the condition -> if condition is true return mu or lambda, else 0.
	return C;
}

template <int dim>
inline SymmetricTensor<2, dim>
get_B_tensor( const FEValues<dim> &fe_values,const unsigned int shape_func,const unsigned int q_point){
	/* this is the B-Matrix or the B-vector in the integral
		K_ij^el = \int_{\Omega} \vec{B}_i \mat{C} \vec{B}_j dx
	 which might be reffered to as strains since we have
	 \int_{\Omega} \eta_{i,j} \sigma_{ij} dV = \int_{Omega} \eta_j t_j dA
	 \int_{\Omega} \frac{1}{2}[\eta_{i,j} + \eta_{j,i}] \sigma_{ij} dV = \int_{Omega} \eta_j t_j dA
	 \int_{\Omega} \varepsilon^{\eta}_{ab} \sigma_{ab} dV = \int_{Omega} \eta_j t_j dA
	 with u_a = \varphi_{aj} u^F_j where u^F_j are the to be determined degrees of freedom
	 and  \eta_b = \varphi_{aj} \eta^F_j where \eta^F_j are the arbitraray values of the test functions
	 we have \varepsilon_{ab} = \frac{1}{2}[u_{a,b}+u_{b,a}] = \frac{1}{2}[\varphi_{aj,b}+\varphi_{bj,a}] u^F_j
	         \varepsilon_{ab} = B_{ajb} u^F_j
	 and     \varepsilon_{ab}^\eta = \frac{1}{1}[\eta_{a,b}+\eta_{b,a}] = = \frac{1}{2}[\varphi_{ai,b}+\varphi_{bi,a}] \eta^F_i
	 		 \varepsilon_{ab}^\eta = B_{aib} \eta^F_i
	 now we plugin these expressions into the integral with \sigma_{ab} = C_abmn and get
	 \eta^F_i \int_{\Omega} B_{aib} C_{abmn} B_{mjn} dV u^F_j = \eta^F_i \int_{Omega}  \varphi_{ai} t_a dA
	 \eta^F_i K_ij u^F_j = \eta^F_i F_i
	 which must hold for all \eta^F_i such that we get
	 K_ij u^F_j = F_i

	 This function implements the quantity B_{ikj}(x_q)=B_{ij} for a given shape function k associated with a dof 
	 and given x_q (quadrature point) such that B_{ij} is a second order Tensor w.r.t. i and j which can be used
	 for the double contraction with the stiffness tensor C_{ijkl}
	*/
	SymmetricTensor<2, dim> B;
	// normal components
	for (unsigned int i = 0; i < dim; ++i)
		B[i][i] = fe_values.shape_grad_component(shape_func, q_point, i)[i];
	// shear components
	for (unsigned int i = 0; i < dim; ++i)
		for (unsigned int j = i + 1; j < dim; ++j)
			B[i][j] = ( fe_values.shape_grad_component(shape_func, q_point, i)[j] +
						      fe_values.shape_grad_component(shape_func, q_point, j)[i]) /2;
	return B;
}

template <int dim>
void ElasticProblem<dim>::assemble_system(){
  QGauss<dim> quadrature_formula(fe.degree + 1);
  FEValues<dim> fe_values(fe,
                          quadrature_formula,
                          update_values | update_gradients |
                          update_quadrature_points | update_JxW_values);
  const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
  const unsigned int n_q_points    = quadrature_formula.size();

  FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
  Vector<double>     cell_rhs(dofs_per_cell);

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

  const auto C_0 = get_stress_strain_tensor<dim>(this->E,this->nu);

  for (const auto &cell : dof_handler.active_cell_iterators()){
      cell_matrix = 0;
      cell_rhs    = 0;
      fe_values.reinit(cell);
      const unsigned int n_dof_per_cell = cell->get_fe().dofs_per_cell;
      for (unsigned int q = 0; q < n_q_points; ++q){
        for (unsigned int i=0; i<n_dof_per_cell; ++i){
          for (unsigned int j=0; j<n_dof_per_cell; ++j){
            const auto B_i = get_B_tensor<dim>(fe_values, i, q);
            const auto B_j = get_B_tensor<dim>(fe_values, j, q);

            cell_matrix(i,j) += ( B_i * C_0 * B_j )*fe_values.JxW(q);
          }
        }
      }
      cell->get_dof_indices(local_dof_indices);
      constraints.distribute_local_to_global(cell_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs);
  }
}
 
template <int dim>
void ElasticProblem<dim>::solve(){

	SparseDirectUMFPACK A_direct;
	A_direct.initialize(this->system_matrix);
	A_direct.vmult(this->solution, this->system_rhs);
  constraints.distribute(solution);
}
// POST-PROCESSING
template<unsigned int dim>
class StressPostprocessor : public  <dim>{
	public:
		StressPostprocessor(double E,double nu);
    double E,nu;
		virtual void evaluate_vector_field( const DataPostprocessorInputs::Vector<dim> &inputs,
											std::vector<Vector<double>> &computed_quantities) const override;

		virtual std::vector<std::string> get_names() const override;

		virtual std::vector<DataComponentInterpretation::DataComponentInterpretation>get_data_component_interpretation() const override;

		virtual UpdateFlags get_needed_update_flags() const override;
};

template <unsigned int dim>
StressPostprocessor<dim>::StressPostprocessor(double E,double nu)
  : E(E)
  , nu(nu)
{}

template <unsigned int dim>
std::vector<std::string> StressPostprocessor<dim>::get_names() const
{
        std::vector<std::string> solution_names;
        solution_names.emplace_back("sig_11");
        solution_names.emplace_back("sig_22");
        solution_names.emplace_back("sig_33");
        solution_names.emplace_back("sig_12");
        solution_names.emplace_back("sig_13");
        solution_names.emplace_back("sig_23");
        solution_names.emplace_back("Mises");
        return solution_names;
}

template <unsigned int dim>
std::vector<DataComponentInterpretation::DataComponentInterpretation> StressPostprocessor<dim>::get_data_component_interpretation() const
{	
    std::vector<DataComponentInterpretation::DataComponentInterpretation>  interpretation(7,DataComponentInterpretation::component_is_scalar);
	return interpretation;
}

template <unsigned int dim>
UpdateFlags StressPostprocessor<dim>::get_needed_update_flags() const{
    return update_gradients;
}

template <unsigned int dim>
void StressPostprocessor<dim>::evaluate_vector_field(const DataPostprocessorInputs::Vector<dim> &inputs,
                                                     std::vector<Vector<double>> &computed_quantities) const{
	AssertDimension(computed_quantities.size(), inputs.solution_gradients.size());
	const unsigned int n_quadrature_points = inputs.solution_values.size();
	const auto C_0 = get_stress_strain_tensor<3>(this->E,this->nu);

  for (unsigned int q = 0; q < n_quadrature_points; ++q){
    Tensor<2, dim> grad_u;
    for (unsigned int d = 0; d < dim; ++d)
      grad_u[d] = inputs.solution_gradients[q][d];
    const SymmetricTensor<2, dim> strain_dim = symmetrize(grad_u);
    SymmetricTensor<2, 3> strain;
    if (dim<3){// plain strain
      for(unsigned int k=0;k<dim;++k)
        for (unsigned int l=0;l<dim;++l)
          strain[k][l] = strain_dim[k][l];
    }
    const SymmetricTensor<2, 3> stress= C_0 * strain;

    computed_quantities[q](0) = stress[0][0];
    computed_quantities[q](1) = stress[1][1];
    computed_quantities[q](2) = stress[2][2];
    computed_quantities[q](3) = stress[0][1];
    computed_quantities[q](4) = stress[0][2];
    computed_quantities[q](5) = stress[1][2];
    computed_quantities[q](6) = std::sqrt(3./2.)*deviator(stress).norm(); // mises stress
  }

}

template <int dim>
void ElasticProblem<dim>::output_results() const{
  DataOut<dim> data_out;
  data_out.attach_dof_handler (dof_handler);
  
  std::vector<DataComponentInterpretation::DataComponentInterpretation> data_component_interpretation(dim, DataComponentInterpretation::component_is_part_of_vector);
  data_out.add_data_vector (solution,
                            std::vector<std::string>(dim,"displacement"),
                            DataOut<dim>::type_dof_data,
                            data_component_interpretation);

  StressPostprocessor<dim> stress_post(this->E,this->nu);
	data_out.add_data_vector(solution, stress_post);




  data_out.build_patches ();
  std::ofstream output("solution.vtu");
  data_out.write_vtu(output);
}
 
template <int dim>
void ElasticProblem<dim>::run(){
	const double half_edge_length = 0.5;
	const double inner_radius     = 0.1;
	GridGenerator::hyper_cube_with_cylindrical_hole(triangulation,
                                                  inner_radius,	  // inner_radius
                                                  half_edge_length, // half the edge length of the square
                                                  0.5,			  // extension in z-dir
                                                  1,				  // repetion in z-dir
                                                  false			  // colorize
                                                  );
  triangulation.refine_global(2);
  std::cout << "   Number of active cells:       "
            << triangulation.n_active_cells() << std::endl;

  setup_system();

  std::cout << "   Number of degrees of freedom: " << dof_handler.n_dofs()
            << std::endl;

  assemble_system();
  solve();
  output_results();
  }
} // namespace Step8

int main(){
  try
    {
      Step8::ElasticProblem<2> elastic_problem_2d;
      elastic_problem_2d.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;
}

Reply via email to