Hi all, I am attaching the sequential and parallel codes as well as parameters.prm file. It would be appreciated if you could compare tangent_matrix (the system_matrix of the elasticity part of the problem) of parallel and sequential codes to find out where I have ruined the S.P.D condition that the parallel code is no longer solved by SolverCG+SSOR.
The code is somehow similar to a Thermoelastic problem at large strains. The sequential code is based on steps 25, 18 and 44 and the parallelization has been done based on step-40. P.S. : All the matrices or vectors which have suffix "eta" such as "solution_eta" or "system_matrix_eta" are related to the thermal part and the ones without suffix are related to elastic part. Thank you very much for your time. Best, Hamed -- 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 [email protected]. For more options, visit https://groups.google.com/d/optout.
#include <deal.II/base/function.h>
#include <deal.II/base/parameter_handler.h>
#include <deal.II/base/point.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/symmetric_tensor.h>
#include <deal.II/base/tensor.h>
#include <deal.II/base/timer.h>
#include <deal.II/base/work_stream.h>
#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/std_cxx11/shared_ptr.h>
#include <deal.II/base/logstream.h>
#include <deal.II/base/utilities.h>
#include <deal.II/base/index_set.h>
#include <deal.II/lac/generic_linear_algebra.h>
namespace LA
{
#if defined(DEAL_II_WITH_PETSC) && !(defined(DEAL_II_WITH_TRILINOS) && defined(FORCE_USE_OF_TRILINOS))
using namespace dealii::LinearAlgebraPETSc;
# define USE_PETSC_LA
#elif defined(DEAL_II_WITH_TRILINOS)
using namespace dealii::LinearAlgebraTrilinos;
#else
# error DEAL_II_WITH_PETSC or DEAL_II_WITH_TRILINOS required
#endif
}
#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/constraint_matrix.h>
#include <deal.II/lac/compressed_sparsity_pattern.h>
#include <deal.II/lac/precondition_selector.h>
#include <deal.II/lac/sparse_direct.h>
#include <deal.II/lac/sparsity_tools.h>
#include <deal.II/lac/trilinos_sparse_matrix.h>
#include <deal.II/lac/trilinos_vector.h>
#include <deal.II/lac/trilinos_precondition.h>
#include <deal.II/lac/trilinos_solver.h>
#include <deal.II/lac/petsc_parallel_sparse_matrix.h>
#include <deal.II/lac/petsc_parallel_vector.h>
#include <deal.II/lac/petsc_solver.h>
#include <deal.II/lac/petsc_precondition.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/grid/grid_in.h>
#include <deal.II/grid/tria.h>
#include <deal.II/grid/tria_boundary_lib.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/dofs/dof_renumbering.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_dgq.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/fe/fe_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/mapping_q_eulerian.h>
#include <deal.II/fe/mapping_q.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/matrix_tools.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/distributed/grid_refinement.h>
#include <iostream>
#include <fstream>
//////////////////////////////////////////////////////////////////
namespace PhaseField
{
using namespace dealii;
// INPUT OF PARAMETERS
namespace Parameters
{
struct FESystem
{
unsigned int poly_degree;
unsigned int quad_order;
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void FESystem::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Finite element system");
{
prm.declare_entry("Polynomial degree", "1",
Patterns::Integer(0),
"Displacement system polynomial order");
prm.declare_entry("Quadrature order", "2",
Patterns::Integer(0),
"Gauss quadrature order");
}
prm.leave_subsection();
}
void FESystem::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Finite element system");
{
poly_degree = prm.get_integer("Polynomial degree");
quad_order = prm.get_integer("Quadrature order");
}
prm.leave_subsection();
}
////////////////////////////////////////////////////
struct Geometry
{
unsigned int refinement;
double scale;
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void Geometry::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Geometry");
{
prm.declare_entry("Global refinement", "4",
Patterns::Integer(0),
"Global refinement level");
prm.declare_entry("Grid scale", "1e-9",
Patterns::Double(0.0),
"Global grid scaling factor");
}
prm.leave_subsection();
}
void Geometry::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Geometry");
{
refinement = prm.get_integer("Global refinement");
scale = prm.get_double("Grid scale");
}
prm.leave_subsection();
}
/////////////////////////////////////////////////
struct Materials
{
double lambda0; // austenite phase
double mu0; // austenite phase
double lambda1; // martensite phase
double mu1; // martensite phase
double L; // interface mobility
double beta; // gradient energy coefficient
double A0; // parameter for barrier height
double theta; // temperature
double thetac; // critical temperature
double thetae; // equilibrium temperature
double thetan; // Crank-Nicolson parameter
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void Materials::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Material properties");
{
prm.declare_entry("lambda austenite", "144.0e9", /* */
Patterns::Double(),
"lambda austenite");
prm.declare_entry("mu austenite", "74.0e9",
Patterns::Double(0.0),
"mu austenite");
prm.declare_entry("lambda martensite", "379.0e9",
Patterns::Double(),
"lambda martensite");
prm.declare_entry("mu martensite", "134.0e9",
Patterns::Double(0.0),
"mu martensite");
prm.declare_entry("kinetic coeff", "2600.0",
Patterns::Double(0.0),
"kinetic coeff");
prm.declare_entry("energy coeff", "2.59e-10",
Patterns::Double(0.0),
"energy coeff");
prm.declare_entry("barrier height", "28.0e6",
Patterns::Double(),
"barrier height");
prm.declare_entry("temperature", "50.0",
Patterns::Double(0.0),
"temperature");
prm.declare_entry("temperature crit", "-183.0",
Patterns::Double(),
"temperature crit");
prm.declare_entry("temperature eql", "215.0",
Patterns::Double(),
"temperature eql");
prm.declare_entry("crank-nicolson parameter", "0.5",
Patterns::Double(),
"crank-nicolson parameter");
}
prm.leave_subsection();
}
void Materials::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Material properties");
{
lambda0 = prm.get_double("lambda austenite");
mu0 = prm.get_double("mu austenite");
lambda1 = prm.get_double("lambda martensite");
mu1 = prm.get_double("mu martensite");
L = prm.get_double("kinetic coeff");
beta = prm.get_double("energy coeff");
A0 = prm.get_double("barrier height");
theta = prm.get_double("temperature");
thetac = prm.get_double("temperature crit");
thetae = prm.get_double("temperature eql");
thetan = prm.get_double("crank-nicolson parameter");
}
prm.leave_subsection();
}
/////////////////////////////////////////////////
struct Time
{
double delta_t;
double end_time;
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void Time::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Time");
{
prm.declare_entry("End time", "2e-12",
Patterns::Double(),
"End time");
prm.declare_entry("Time step size", "1e-14",
Patterns::Double(),
"Time step size");
}
prm.leave_subsection();
}
void Time::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Time");
{
end_time = prm.get_double("End time");
delta_t = prm.get_double("Time step size");
}
prm.leave_subsection();
}
///////////////////////////////////////////////////////
struct AllParameters : public FESystem,
public Geometry,
public Materials,
public Time
{
AllParameters(const std::string &input_file);
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
AllParameters::AllParameters(const std::string &input_file)
{
ParameterHandler prm;
declare_parameters(prm);
prm.read_input(input_file);
parse_parameters(prm);
}
void AllParameters::declare_parameters(ParameterHandler &prm)
{
FESystem::declare_parameters(prm);
Geometry::declare_parameters(prm);
Materials::declare_parameters(prm);
Time::declare_parameters(prm);
}
void AllParameters::parse_parameters(ParameterHandler &prm)
{
FESystem::parse_parameters(prm);
Geometry::parse_parameters(prm);
Materials::parse_parameters(prm);
Time::parse_parameters(prm);
}
}
// DEFINE SECOND ORDER IDENTITY, AND TWO FOURTH ORDER IDENTITY TENSORS
template <int dim>
class StandardTensors
{
public:
static const SymmetricTensor<2, dim> I;
static const SymmetricTensor<4, dim> IxI;
static const SymmetricTensor<4, dim> II;
// static const SymmetricTensor<2, dim> transformation_strain;
};
template <int dim>
const SymmetricTensor<2, dim>
StandardTensors<dim>::I = unit_symmetric_tensor<dim>();
template <int dim>
const SymmetricTensor<4, dim>
StandardTensors<dim>::IxI = outer_product(I, I);
template <int dim>
const SymmetricTensor<4, dim>
StandardTensors<dim>::II = identity_tensor<dim>();
// DEFINE TIME STEP, CURRENT TIME ETC.
class Time
{
public:
Time (const double time_end,
const double delta_t)
:
timestep(0),
time_current(0.0),
time_end(time_end),
delta_t(delta_t)
{}
virtual ~Time()
{}
double current() const
{
return time_current;
}
double end() const
{
return time_end;
}
double get_delta_t() const
{
return delta_t;
}
unsigned int get_timestep() const
{
return timestep;
}
void increment()
{
time_current += delta_t;
++timestep;
}
private:
unsigned int timestep;
double time_current;
const double time_end;
const double delta_t;
};
//////////////////////////////////////////////////////////
template <int dim>
class Material_Compressible_Neo_Hook_Three_Field
{
public:
Material_Compressible_Neo_Hook_Three_Field(const double lambda0,
const double mu0,
const double lambda1,
const double mu1,
const double A0,
const double theta,
const double thetac,
const double thetae)
:
det_F(1.0),
I1(0.0), // I1 = trace(Be)
ge(StandardTensors<dim>::I), // = Fe.Fe^T
Be(SymmetricTensor<2, dim>()), // = 0.5(Fe.Fe^T-I)
lambda00(lambda0),
mu00(mu0),
lambda11(lambda1),
mu11(mu1),
A00(A0),
theta1(theta),
thetac1(thetac),
thetae1(thetae)
{}
~Material_Compressible_Neo_Hook_Three_Field()
{}
void update_material_data (const Tensor<2, dim> &F, const Tensor<2, dim> &Fe,
const double phi, const double dphi,const double ddphi,
const double dPotentialBarrier, const double ddPotentialBarrier)
{
det_F = determinant(F); // determinant of total F
ge = symmetrize(Fe*transpose(Fe)); // ge = Fe.Fe^T
Be = 0.5*(ge-StandardTensors<dim>::I); // Be = 1/2(ge-I)
I1 = trace(Be); // first invariant of Be
lambda = lambda00+(lambda11-lambda00)*phi; // definition of the Lame constants are obvious
mu = mu00+(mu11-mu00)*phi;
deltaG = A00*(theta1-thetae1)/3.0; // difference in thermal energy
A = A00*(theta1-thetac1); // compute barrier height
dphi1 = dphi; // d_phi/d_eta
ddphi1 = ddphi;
dPotentialBarrier1 = dPotentialBarrier;
ddPotentialBarrier1 = ddPotentialBarrier;
Assert(det_F > 0, ExcInternalError());
}
SymmetricTensor<2, dim> get_tau() // tau is the Kirchhoff stress := J*Cauchy stress
{
return get_tau_kirchhoff();
}
SymmetricTensor<4, dim> get_Jc() const // comupte the fourth order modulus tensor in the deformed config.
{
return get_Jc_modulus();
}
double get_det_F() const
{
return det_F;
}
double get_driving_force_noStress() const // driving force excluding the transformational work
{
return get_driv_forc_noStress ();
}
double get_deri_driving_force_noStress() const // driving force excluding the transformational work
{
return get_deri_driv_forc_noStress ();
}
protected:
double det_F;
double I1;
SymmetricTensor<2, dim> ge;
SymmetricTensor<2, dim> Be;
double lambda00;
double mu00;
double lambda11;
double mu11;
double A00;
double theta1;
double thetac1;
double thetae1;
double lambda;
double mu;
double deltaG;
double A;
double dphi1;
double ddphi1;
double dPotentialBarrier1;
double ddPotentialBarrier1;
// compute the Kirchhoff stress
SymmetricTensor<2, dim> get_tau_kirchhoff() const
{
SymmetricTensor<2, dim> kirchhoff_stress = lambda*I1*ge +
mu*symmetrize(Tensor<2, dim>(ge) * Tensor<2, dim>(ge))-mu*ge;
return kirchhoff_stress;
}
// compute the modulus J*d_ijkl
SymmetricTensor<4, dim> get_Jc_modulus() const
{
SymmetricTensor<4,dim> elasticityTensor;
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)
elasticityTensor[i][j][k][l] =
lambda*ge[i][j]*ge[k][l]+mu*(ge[i][l]*ge[j][k]+ge[i][k]*ge[j][l]);
return elasticityTensor;
}
// compute the driving force excluding the transformational work
double get_driv_forc_noStress () const
{
return -A*dPotentialBarrier1-deltaG*dphi1;
}
double get_deri_driv_forc_noStress () const
{
return -A*ddPotentialBarrier1-deltaG*ddphi1;
}
};
// updates the quadrature point history
template <int dim>
class PointHistory
{
public:
PointHistory()
:
material(NULL),
F_inv(StandardTensors<dim>::I),
tau(SymmetricTensor<2, dim>()),
Jc(SymmetricTensor<4, dim>())
{}
virtual ~PointHistory()
{
delete material;
material = NULL;
}
void setup_lqp (const Parameters::AllParameters ¶meters)
{
material = new Material_Compressible_Neo_Hook_Three_Field<dim>(parameters.lambda0,
parameters.mu0, parameters.lambda1, parameters.mu1, parameters.A0,
parameters.theta, parameters.thetac, parameters.thetae);
update_values(Tensor<2, dim>(), double (), double (), double());
}
void update_values (const Tensor<2, dim> &Grad_u_n,
const double new_eta,
const double old_eta,
const double thetan)
{
double eta = thetan*new_eta +(1-thetan)*old_eta;
const double phi = 3*eta*eta-2*eta*eta*eta; // interpolation function
const double dphi = 6*eta-6*eta*eta; // derivative of interpolation fn
const double ddphi = 6-12*eta;
const double dPotentialBarrier = 2*eta-6*eta*eta+4*eta*eta*eta;
const double ddPotentialBarrier =2-12*eta+12*eta*eta;
// double strectch1 = 0.8;
// double strectch2 = 1.2;
Tensor<2, dim> tmp; // transformation strain tensor
// tmp[0][0] = pow(strectch1, 1.5)/(1.0+strectch1) + pow(strectch2, 1.5)/(1.0+strectch2)-1.0;
// tmp[1][1] = pow(strectch1, 0.5)/(1.0+strectch1) + pow(strectch2, 0.5)/(1.0+strectch2)-1.0;
// tmp[2][2] = 0.0;
// tmp[0][1] = -strectch1/(1.0+strectch1) + strectch2/(1.0+strectch2);
// tmp[1][0] = -strectch1/(1.0+strectch1) + strectch2/(1.0+strectch2);
// tmp[0][2] = 0.0;
// tmp[2][0] = 0.0;
// tmp[1][2] = 0.0;
// tmp[2][1] = 0.0;
//
tmp[0][0] = 0.1;
tmp[1][1] = -0.05;
tmp[2][2] = -0.05;
tmp[0][1] = 0.0;
tmp[1][0] = 0.0;
tmp[0][2] = 0.0;
tmp[2][0] = 0.0;
tmp[1][2] = 0.0;
tmp[2][1] = 0.0;
SymmetricTensor<2, dim> transStrain = symmetrize(tmp);
const Tensor<2, dim> Ft = (Tensor<2, dim>(StandardTensors<dim>::I) +
Tensor<2, dim>(transStrain)*phi); // transformation deformation gradient
F = (Tensor<2, dim>(StandardTensors<dim>::I) + Grad_u_n); // total F
Fe = F * invert(Ft); // elastic part of deformation grad
material->update_material_data(F, Fe, phi, dphi, ddphi, dPotentialBarrier, ddPotentialBarrier);
F_inv = invert(F);
tau = material->get_tau(); // extracting kirchhoff stress
Jc = material->get_Jc(); // extracting J*d_ijkl
driving_force_noStress = material->get_driving_force_noStress(); // extracting driving force with no stress
deri_driving_force_noStress = material->get_deri_driving_force_noStress();
const Tensor<2, dim> temp_tensor = F_inv*Tensor<2, dim>(tau);
const Tensor<2, dim> temp_tensor1 = temp_tensor * Fe;
get_driv_forc = scalar_product(temp_tensor1, tmp)*dphi + driving_force_noStress; // computing total driving force
get_deri_driv_forc = scalar_product(temp_tensor1, tmp)*ddphi + deri_driving_force_noStress;
Assert(determinant(F_inv) > 0, ExcInternalError());
}
const Tensor<2, dim> &get_F() const
{
return F;
}
double get_det_F() const
{
return material->get_det_F();
}
const Tensor<2, dim> &get_F_inv() const
{
return F_inv;
}
const SymmetricTensor<2, dim> &get_tau() const
{
return tau;
}
const SymmetricTensor<4, dim> &get_Jc() const
{
return Jc;
}
double get_driving_force() const
{
return get_driv_forc;
}
double get_deri_driving_force() const
{
return get_deri_driv_forc;
}
private:
Material_Compressible_Neo_Hook_Three_Field<dim> *material;
Tensor<2, dim> F_inv;
Tensor<2, dim> F;
SymmetricTensor<2, dim> tau;
SymmetricTensor<4, dim> Jc;
Tensor<2, dim> Fe;
double driving_force_noStress;
double deri_driving_force_noStress;
double dphi;
double ddphi;
double get_driv_forc;
double get_deri_driv_forc;
};
///////////////////////////////////////////////////////////////
template <int dim>
class Solid
{
public:
Solid(const std::string &input_file);
virtual
~Solid();
void
run();
private:
void make_grid();
void system_setup();
void assemble_system();
void make_constraints(const int &it_nr);
void solve_nonlinear_timestep();
unsigned int solve();
void assemble_system_eta();
void solve_nonlinear_timestep_eta();
unsigned int solve_eta();
void setup_qph();
void update_qph_incremental();
void output_results() const;
Parameters::AllParameters parameters;
double vol_reference; // volume of the reference config
double vol_current; // volume of the current config
Time time; // variable of type class 'Time'
//TimerOutput timer;
MPI_Comm mpi_communicator;
parallel::distributed::Triangulation<dim> triangulation;
ConditionalOStream pcout;
const unsigned int degree; // degree of polynomial of shape functions
const FESystem<dim> fe; // fe object
DoFHandler<dim> dof_handler; // we have used two dof_handler: one for mechanics another for order parameter
const unsigned int dofs_per_cell; // no of dofs per cell for the mechanics problem
const FEValuesExtractors::Vector u_fe;
const QGauss<dim> qf_cell; // quadrature points in the cell
const QGauss<dim - 1> qf_face; // quadrature points at the face
const unsigned int n_q_points; // no of quadrature points in the cell
const unsigned int n_q_points_f; // no of quadrature points at the face
ConstraintMatrix constraints; // constraint object
FE_DGQ<dim> history_fe;
DoFHandler<dim> history_dof_handler;
std::vector<PointHistory<dim> > quadrature_point_history;
IndexSet locally_owned_dofs;
IndexSet locally_relevant_dofs;
LA::MPI::SparseMatrix tangent_matrix; // tangent stiffenss matrix
LA::MPI::Vector system_rhs; // system right hand side or residual of mechanics problem
LA::MPI::Vector solution; // solution vector for displacement
LA::MPI::Vector solution_update; // another vector containing the displacement soln
LA::MPI::Vector tmp;
const unsigned int degree_eta; // degree of polynomial for eta
FE_Q<dim> fe_eta; // fe object for eta
DoFHandler<dim> dof_handler_eta; //another dof_handler for eta
const unsigned int dofs_per_cell_eta; // dof per eta cell
const QGauss<dim> qf_cell_eta;
const unsigned int n_q_points_eta;
IndexSet locally_owned_dofs_eta;
IndexSet locally_relevant_dofs_eta;
LA::MPI::SparseMatrix mass_matrix; // mass matrix out of Ginxburg-Landau eqn
LA::MPI::SparseMatrix laplace_matrix; // Laplace matrix out of Ginxburg-Landau eqn
LA::MPI::SparseMatrix system_matrix_eta;
LA::MPI::SparseMatrix nl_matrix;
LA::MPI::SparseMatrix tmp_matrix;
LA::MPI::Vector nl_term;
LA::MPI::Vector system_rhs_eta;
LA::MPI::Vector solution_eta; // solution vector for eta
LA::MPI::Vector old_solution_eta;
LA::MPI::Vector solution_update_eta;
LA::MPI::Vector tmp_vector; // a vector used for solving eta
LA::MPI::Vector tmp_eta;
};
/////////////////////////////////////////////////////////
// defines the initial condition for the order parameter
template <int dim>
class InitialValues : public Function<dim>
{
public:
InitialValues () : Function<dim>() {}
virtual double value(const Point<dim> &p,
const unsigned int /*component = 0*/) const;
};
template <int dim>
double InitialValues<dim>::value (const Point<dim> &p,
const unsigned int /*component*/) const
{
// return 0.0;
// return 0.01;
return (rand()%100+0.0)*0.01;
// if ((p[0] > 2.5e-9) && (p[1] > 2.5e-9) && (p[0] < 7.5e-9) && (p[1] < 7.5e-9))
// return 1;
// else
// return 0;
////
// return
// -std::max(std::min(-tanh((sqrt((p[0]-3.0e-9)*(p[0]-3.0e-9)+(p[1]-3.0e-9)*(p[1]-3.0e-9))-1.0e-9)/0.4e-9),0.0),
// std::min(-tanh((sqrt((p[0]-7.0e-9)*(p[0]-7.0e-9)+(p[1]-3.0e-9)*(p[1]-3.0e-9))-1.0e-9)/0.4e-9),0.0));
// return std::max(tanh((1e-9-sqrt((p[0]-5.0e-9)*(p[0]-5.0e-9)+(p[1]-5.0e-9)*(p[1]-5.0e-9)))/0.4e-9),0.0);
//return (0.5*std::tanh(3.0*(p[0]-5.0e-9)/7.07e-10)+0.5);
// return 0.1 * std::max(tanh((p[0]-5.0e-9)/(0.4e-9)), 0.0);
// return 0.5*std::tanh(p[0]/(0.4e-9))+0.5;
}
/////////////////////////////////////////////////
template <int dim>
class BoundaryDisplacement : public Function<dim>
{
public:
BoundaryDisplacement (const int direction, const int time_step);
virtual
void
vector_value (const Point<dim> &p,
Vector<double> &values) const;
virtual
void
vector_value_list (const std::vector<Point<dim> > &points,
std::vector<Vector<double> > &value_list) const;
private:
const int direction;
const int time_step;
};
template <int dim>
BoundaryDisplacement<dim>::BoundaryDisplacement (const int direction,const int time_step)
:
Function<dim> (dim),
direction(direction),
time_step(time_step)
{}
template <int dim>
inline
void
BoundaryDisplacement<dim>::vector_value (const Point<dim> &/*p*/,
Vector<double> &values) const
{
Assert (values.size() == dim,
ExcDimensionMismatch (values.size(), dim));
values = 0;
if (time_step <3)
values(direction) = 0.1e-9;
else
values(direction)= 0.001e-9;
}
template <int dim>
void
BoundaryDisplacement<dim>::vector_value_list (const std::vector<Point<dim> > &points,
std::vector<Vector<double> > &value_list) const
{
const unsigned int n_points = points.size();
Assert (value_list.size() == n_points,
ExcDimensionMismatch (value_list.size(), n_points));
for (unsigned int p=0; p<n_points; ++p)
BoundaryDisplacement<dim>::vector_value (points[p],
value_list[p]);
}
//////////////////////////////////////////////////
// constructor
template <int dim>
Solid<dim>::Solid(const std::string &input_file)
:
mpi_communicator (MPI_COMM_WORLD),
triangulation (mpi_communicator,
typename Triangulation<dim>::MeshSmoothing
(Triangulation<dim>::smoothing_on_refinement |
Triangulation<dim>::smoothing_on_coarsening)),
parameters(input_file),
time(parameters.end_time, parameters.delta_t),
pcout (std::cout,
(Utilities::MPI::this_mpi_process(mpi_communicator)
== 0)),
// timer(mpi_communicator,
// pcout,
// TimerOutput::summary,
// TimerOutput::wall_times),
degree(parameters.poly_degree),
fe(FE_Q<dim>(parameters.poly_degree), dim), // displacement
dof_handler(triangulation),
dofs_per_cell (fe.dofs_per_cell),
u_fe(0),
qf_cell(parameters.quad_order),
qf_face(parameters.quad_order),
n_q_points (qf_cell.size()),
n_q_points_f (qf_face.size()),
degree_eta(parameters.poly_degree),
fe_eta (parameters.poly_degree),
dof_handler_eta (triangulation),
dofs_per_cell_eta(fe_eta.dofs_per_cell),
qf_cell_eta(parameters.quad_order),
n_q_points_eta (qf_cell_eta.size()),
history_dof_handler (triangulation),
history_fe (parameters.poly_degree)
{}
//destructor
template <int dim>
Solid<dim>::~Solid()
{
dof_handler.clear();
dof_handler_eta.clear();
}
//////////////////////////////////////////////////
template <int dim>
void Solid<dim>::run()
{
make_grid(); // generates the geometry and mesh
system_setup(); // sets up the system matrices
VectorTools::interpolate(dof_handler_eta, InitialValues<dim>(), tmp_eta); //initial eta
solution_eta= tmp_eta;
old_solution_eta = solution_eta;
update_qph_incremental();
// this is the zeroth iteration for compute the initial distorted solution
//of the body due to arbitrary distribution of initial eta
solve_nonlinear_timestep();
output_results();
time.increment();
// computed actual time integration to update displacement and eta
while (time.current() <= time.end())
{
pcout << std::endl
<< "Time step #" << time.get_timestep() << "; "
<< "advancing to t = " << time.current() << "."
<< std::endl;
solve_nonlinear_timestep_eta();
solve_nonlinear_timestep();
output_results();
time.increment();
}
}
///////////////////////////////////
template <int dim>
void Solid<dim>::solve_nonlinear_timestep()
{
double initial_rhs_norm = 0.;
unsigned int newton_iteration = 0;
for (; newton_iteration < 20; ++newton_iteration)
{
assemble_system ();
make_constraints(newton_iteration);
if (newton_iteration == 0)
initial_rhs_norm = system_rhs.l2_norm();
std::cout<<"right hand side norm : "<<system_rhs.l2_norm()<<std::endl;
const unsigned int n_iterations
= solve ();
LA::MPI::Vector temp_solution_update(locally_owned_dofs, mpi_communicator);
temp_solution_update = solution_update;
tmp += temp_solution_update;
solution = tmp;
update_qph_incremental();
// if (newton_iteration == 0)
// std::cout << " Solving for Displacement: " << n_iterations;//<<std::endl;
// else
// std::cout << '+' << n_iterations;//<<std::endl;
if (newton_iteration > 0 && system_rhs.l2_norm() <= 1e-6 * initial_rhs_norm)
{
std::cout << " CG iterations per nonlinear step. CONVERGED! " << std::endl;
break;
}
AssertThrow (newton_iteration < 19,
ExcMessage("No convergence in nonlinear solver!"));
}
}
/////////////////////////////////////////
template <int dim>
void Solid<dim>::solve_nonlinear_timestep_eta()
{
old_solution_eta = solution_eta;
double initial_rhs_norm = 0.;
unsigned int newton_iteration = 0;
for (; newton_iteration < 20; ++newton_iteration)
{
assemble_system_eta ();
if (newton_iteration == 0)
initial_rhs_norm = system_rhs_eta.l2_norm();
const unsigned int n_iterations
= solve_eta ();
LA::MPI::Vector temp_solution_update_eta(locally_owned_dofs, mpi_communicator);
temp_solution_update_eta = solution_update_eta;
tmp_eta += temp_solution_update_eta;
solution_eta= tmp_eta;
update_qph_incremental();
if (newton_iteration == 0)
std::cout << " Solving for Order Parameter: " << n_iterations;
else
std::cout << '+' << n_iterations;
if (newton_iteration > 0 && system_rhs_eta.l2_norm() <= 1e-6 * initial_rhs_norm)
{
std::cout << " CG iterations per nonlinear step. CONVERGED! " << std::endl;
break;
}
AssertThrow (newton_iteration < 19,
ExcMessage("No convergence in nonlinear solver!"));
}
}
///////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::make_grid()
{
// // Divide the beam, but only along the x- and y-coordinate directions
// std::vector< unsigned int > repetitions(dim, 32);
// // Only allow one element through the thickness
// // (modelling a plane strain condition)
// if (dim == 3)
// repetitions[dim-1] = 1;
//
// const Point<dim> bottom_left = (dim == 3 ? Point<dim>(0.0, 0.0, -0.5) : Point<dim>(0.0, 0.0));
// const Point<dim> top_right = (dim == 3 ? Point<dim>(10.0, 10.0, 0.5) : Point<dim>(10.0, 10.0));
//
// GridGenerator::subdivided_hyper_rectangle(triangulation,
// repetitions,
// bottom_left,
// top_right,
// true);
GridGenerator::hyper_rectangle(triangulation,
Point<dim>(0.0, 0.0, 0.0),
Point<dim>(10.0, 10.0, 10.0),
true);
triangulation.refine_global (parameters.refinement);
GridTools::scale(parameters.scale, triangulation);
}
///////////////////////////////////////////////////
template <int dim>
void Solid<dim>::system_setup()
{
dof_handler.distribute_dofs(fe);
dof_handler_eta.distribute_dofs (fe_eta);
history_dof_handler.distribute_dofs (history_fe);
const unsigned int n_dofs = dof_handler.n_dofs(),
n_dofs_eta = dof_handler_eta.n_dofs();
std::cout << " Number of active cells: "
<< triangulation.n_active_cells()
<< std::endl
<< " Total number of cells: "
<< triangulation.n_cells()
<< std::endl
<< " Number of degrees of freedom: "
<< n_dofs + n_dofs_eta
<< " (" << n_dofs << '+' << n_dofs_eta << ')'
<< std::endl;
locally_owned_dofs = dof_handler.locally_owned_dofs ();
DoFTools::extract_locally_relevant_dofs (dof_handler , locally_relevant_dofs);
DynamicSparsityPattern dsp(locally_relevant_dofs);
DoFTools::make_sparsity_pattern (dof_handler, dsp);
SparsityTools::distribute_sparsity_pattern (dsp,
dof_handler.n_locally_owned_dofs_per_processor(),
mpi_communicator,
locally_relevant_dofs);
tangent_matrix.reinit(locally_owned_dofs,
locally_owned_dofs,
dsp,
mpi_communicator);
solution.reinit(locally_owned_dofs,
locally_relevant_dofs,
mpi_communicator);
solution_update.reinit(locally_owned_dofs,
locally_relevant_dofs,
mpi_communicator);
system_rhs.reinit(locally_owned_dofs,
mpi_communicator);
tmp.reinit(locally_owned_dofs,
mpi_communicator);
locally_owned_dofs_eta = dof_handler_eta.locally_owned_dofs ();
DoFTools::extract_locally_relevant_dofs (dof_handler_eta , locally_relevant_dofs_eta);
DynamicSparsityPattern dsp_eta(locally_relevant_dofs_eta);
DoFTools::make_sparsity_pattern (dof_handler_eta, dsp_eta);
SparsityTools::distribute_sparsity_pattern (dsp_eta,
dof_handler_eta.n_locally_owned_dofs_per_processor(),
mpi_communicator,
locally_relevant_dofs_eta);
mass_matrix.reinit (locally_owned_dofs_eta,
locally_owned_dofs_eta,
dsp_eta,
mpi_communicator);
laplace_matrix.reinit (locally_owned_dofs_eta,
locally_owned_dofs_eta,
dsp_eta,
mpi_communicator);
system_matrix_eta.reinit (locally_owned_dofs_eta,
locally_owned_dofs_eta,
dsp_eta,
mpi_communicator);
nl_matrix.reinit (locally_owned_dofs_eta,
locally_owned_dofs_eta,
dsp_eta,
mpi_communicator);
tmp_matrix.reinit (locally_owned_dofs_eta,
locally_owned_dofs_eta,
dsp_eta,
mpi_communicator);
solution_eta.reinit(locally_owned_dofs_eta,
locally_relevant_dofs_eta,
mpi_communicator);
old_solution_eta.reinit(locally_owned_dofs_eta,
locally_relevant_dofs_eta,
mpi_communicator);
solution_update_eta.reinit(locally_owned_dofs_eta,
locally_relevant_dofs_eta,
mpi_communicator);
system_rhs_eta.reinit(locally_owned_dofs_eta,
mpi_communicator);
nl_term.reinit(locally_owned_dofs_eta,
mpi_communicator);
tmp_vector.reinit(locally_owned_dofs_eta,
mpi_communicator);
tmp_eta.reinit(locally_owned_dofs_eta,
mpi_communicator);
// sets up the quadrature point history
setup_qph();
}
//////////////////////////////////
template <int dim>
void Solid<dim>::make_constraints(const int &it_nr)
{
if (it_nr > 1)
return;
constraints.clear();
constraints.reinit (locally_relevant_dofs);
const bool apply_dirichlet_bc = (it_nr == 0);
const int timestep = time.get_timestep();
const FEValuesExtractors::Scalar x_displacement(0);
const FEValuesExtractors::Scalar y_displacement(1);
const FEValuesExtractors::Scalar z_displacement(2);
{
const int boundary_id = 0;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(x_displacement)/*|
fe.component_mask(y_displacement) |
fe.component_mask(z_displacement)*/);
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(x_displacement)/* |
fe.component_mask(y_displacement) |
fe.component_mask(z_displacement)*/);
}
{
const int boundary_id = 1;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
BoundaryDisplacement<dim>(0, timestep),
constraints,
fe.component_mask(x_displacement));
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(x_displacement));
}
//
//
{
const int boundary_id = 2;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(y_displacement));
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(y_displacement));
}
//
// {
// const int boundary_id = 3;
//
// if (apply_dirichlet_bc == true)
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(y_displacement));
// else
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(y_displacement));
// }
{
const int boundary_id = 4;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(z_displacement));
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(z_displacement));
}
// {
// const int boundary_id = 5;
//
// if (apply_dirichlet_bc == true)
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(z_displacement));
// else
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(z_displacement));
// }
// {
// const double tol_boundary = 0.7e-9;
// typename DoFHandler<dim>::active_cell_iterator
// cell = dof_handler.begin_active(),
// endc = dof_handler.end();
// for (; cell!=endc; ++cell)
// if (cell->is_locally_owned())
// {
// for (unsigned int v=0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
//
// if ((std::abs(cell->vertex(v)[0] - 0.0) < tol_boundary) &&
// (std::abs(cell->vertex(v)[1] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[2] - 5.0e-9) < tol_boundary))
// {
// constraints.add_line(cell->vertex_dof_index(v, 0));
// // constraints.add_line(cell->vertex_dof_index(v, 1));
// // constraints.add_line(cell->vertex_dof_index(v, 2));
// }
//
// else if ((std::abs(cell->vertex(v)[0] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[1] - 0.0) < tol_boundary) &&
// (std::abs(cell->vertex(v)[2] - 5.0e-9) < tol_boundary))
// {
// // constraints.add_line(cell->vertex_dof_index(v, 0));
// constraints.add_line(cell->vertex_dof_index(v, 1));
// //constraints.add_line(cell->vertex_dof_index(v, 2));
// }
//
// else if ((std::abs(cell->vertex(v)[0] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[1] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[2] - 0) < tol_boundary))
// {
// //constraints.add_line(cell->vertex_dof_index(v, 0));
// //constraints.add_line(cell->vertex_dof_index(v, 1));
// constraints.add_line(cell->vertex_dof_index(v, 2));
// }
//
// }
// }
constraints.close();
}
/////////////////////////////////////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::assemble_system ()
{
tangent_matrix = 0;
system_rhs = 0;
FEValues<dim> fe_values (fe, qf_cell,
update_values | update_gradients |
update_quadrature_points | update_JxW_values);
FEFaceValues<dim> fe_face_values (fe, qf_face,
update_values | update_quadrature_points |
update_normal_vectors | update_JxW_values);
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);
std::vector<double> Nx(dofs_per_cell);
std::vector<Tensor<2, dim> > grad_Nx(dofs_per_cell);
std::vector<SymmetricTensor<2, dim> > symm_grad_Nx(dofs_per_cell);
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler.begin_active(),
endc = dof_handler.end();
for (; cell!=endc; ++cell)
if (cell->is_locally_owned())
{
fe_values.reinit (cell);
cell_matrix = 0;
cell_rhs = 0;
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
{
const Tensor<2, dim> F_inv = lqph[q_point].get_F_inv();
const Tensor<2, dim> tau = lqph[q_point].get_tau();
const SymmetricTensor<2, dim> symm_tau = lqph[q_point].get_tau();
const SymmetricTensor<4, dim> Jc = lqph[q_point].get_Jc();
const double JxW = fe_values.JxW(q_point);
for (unsigned int k=0; k<dofs_per_cell; ++k)
{
grad_Nx[k] = fe_values[u_fe].gradient(k, q_point) * F_inv;
symm_grad_Nx[k] = symmetrize(grad_Nx[k]);
}
for (unsigned int i=0; i<dofs_per_cell; ++i)
{
const unsigned int component_i = fe.system_to_component_index(i).first;
for (unsigned int j=0; j<dofs_per_cell; ++j)
{
const unsigned int component_j = fe.system_to_component_index(j).first;
cell_matrix(i, j) += symm_grad_Nx[i] * Jc // The material contribution:
* symm_grad_Nx[j] * JxW;
if (component_i == component_j) // geometrical stress contribution
cell_matrix(i, j) += grad_Nx[i][component_i] * tau
* grad_Nx[j][component_j] * JxW;
}
cell_rhs(i) -= symm_grad_Nx[i] * symm_tau * JxW;
}
}
cell->get_dof_indices (local_dof_indices);
constraints.distribute_local_to_global (cell_matrix,
cell_rhs,
local_dof_indices,
tangent_matrix,
system_rhs);
}
tangent_matrix.compress (VectorOperation::add);
system_rhs.compress (VectorOperation::add);
}
//////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::assemble_system_eta ()
{
system_matrix_eta = 0;
system_rhs_eta = 0;
mass_matrix = 0;
laplace_matrix = 0;
nl_matrix = 0;
nl_term = 0;
FEValues<dim> fe_values_eta (fe_eta, qf_cell_eta,
update_values | update_gradients |
update_quadrature_points | update_JxW_values);
FullMatrix<double> cell_mass_matrix (dofs_per_cell_eta, dofs_per_cell_eta);
FullMatrix<double> cell_laplace_matrix (dofs_per_cell_eta, dofs_per_cell_eta);
FullMatrix<double> cell_nl_matrix (dofs_per_cell_eta, dofs_per_cell_eta);
Vector <double> cell_nl_term (dofs_per_cell_eta);
std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell_eta);
std::vector<double> phi (dofs_per_cell_eta);
std::vector<Tensor<1,dim> > grad_phi (dofs_per_cell_eta);
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler_eta.begin_active(),
endc = dof_handler_eta.end();
for (; cell!=endc; ++cell)
if (cell->is_locally_owned())
{
fe_values_eta.reinit(cell);
cell_mass_matrix = 0;
cell_laplace_matrix = 0;
cell_nl_matrix = 0;
cell_nl_term = 0;
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
for (unsigned int q=0; q<n_q_points_eta; ++q)
{
const double driving_force = lqph[q].get_driving_force();
const double deri_driving_force = lqph[q].get_deri_driving_force();
for (unsigned int k=0; k<dofs_per_cell_eta; ++k)
{
phi[k] = fe_values_eta.shape_value (k, q);
grad_phi[k] = fe_values_eta.shape_grad (k, q);
}
for (unsigned int i=0; i<dofs_per_cell_eta; ++i)
{
for (unsigned int j=0; j<dofs_per_cell_eta; ++j)
{
cell_mass_matrix(i,j) += (phi[i] * phi[j]) * fe_values_eta.JxW(q);
cell_laplace_matrix(i,j) += (grad_phi[i] * grad_phi[j]) * fe_values_eta.JxW(q);
cell_nl_matrix(i,j) += deri_driving_force * phi[i] * phi[j] * fe_values_eta.JxW(q);
}
cell_nl_term(i) += driving_force * phi[i] * fe_values_eta.JxW (q);
}
}
cell->get_dof_indices (local_dof_indices);
for (unsigned int i=0; i<dofs_per_cell_eta; ++i)
{
for (unsigned int j=0; j<dofs_per_cell_eta; ++j)
{
mass_matrix. add (local_dof_indices[i],
local_dof_indices[j],
cell_mass_matrix(i,j));
laplace_matrix.add (local_dof_indices[i],
local_dof_indices[j],
cell_laplace_matrix(i,j));
nl_matrix. add (local_dof_indices[i],
local_dof_indices[j],
cell_nl_matrix(i,j));
}
nl_term (local_dof_indices[i]) += cell_nl_term(i);
}
}
mass_matrix.compress (VectorOperation::add);
laplace_matrix.compress (VectorOperation::add);
nl_matrix.compress (VectorOperation::add);
nl_term.compress (VectorOperation::add);
LA::MPI::Vector temp_solution_eta (locally_owned_dofs_eta, mpi_communicator);
LA::MPI::Vector temp_old_solution_eta (locally_owned_dofs_eta, mpi_communicator);
temp_solution_eta = solution_eta;
temp_old_solution_eta = old_solution_eta;
system_matrix_eta.copy_from (mass_matrix);
system_matrix_eta.add ( laplace_matrix, parameters.L * parameters.beta * parameters.delta_t * parameters.thetan);
system_matrix_eta.add ( nl_matrix, -parameters.L * parameters.delta_t * parameters.thetan);
tmp_matrix.copy_from (mass_matrix);
tmp_matrix.add ( laplace_matrix, parameters.L * parameters.beta * parameters.delta_t * parameters.thetan);
tmp_matrix.vmult (tmp_vector, temp_solution_eta);
system_rhs_eta += tmp_vector;
tmp_matrix.add( laplace_matrix, -parameters.L * parameters.beta * parameters.delta_t);
tmp_matrix.vmult (tmp_vector, temp_old_solution_eta);
system_rhs_eta -= tmp_vector;
system_rhs_eta.add (-parameters.L * parameters.delta_t, nl_term);
system_rhs_eta *= -1;
system_matrix_eta.compress (VectorOperation::add);
system_rhs_eta.compress (VectorOperation::add);
}
///////////////////////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::setup_qph()
{
{
unsigned int our_cells = 0;
for (typename Triangulation<dim>::active_cell_iterator
cell = triangulation.begin_active();
cell != triangulation.end(); ++cell)
if (cell->is_locally_owned())
++our_cells;
triangulation.clear_user_data();
{
std::vector<PointHistory<dim> > tmp;
tmp.swap (quadrature_point_history);
}
quadrature_point_history.resize (our_cells * n_q_points);
unsigned int history_index = 0;
for (typename Triangulation<dim>::active_cell_iterator
cell = triangulation.begin_active();
cell != triangulation.end(); ++cell)
if (cell->is_locally_owned())
{
cell->set_user_pointer(&quadrature_point_history[history_index]);
history_index += n_q_points;
}
Assert(history_index == quadrature_point_history.size(),
ExcInternalError());
}
for (typename Triangulation<dim>::active_cell_iterator
cell = triangulation.begin_active();
cell != triangulation.end(); ++cell)
if (cell->is_locally_owned())
{
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
Assert(lqph >= &quadrature_point_history.front(), ExcInternalError());
Assert(lqph <= &quadrature_point_history.back(), ExcInternalError());
for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
lqph[q_point].setup_lqp(parameters);
}
}
// Updates the data at all quadrature points over a loop run by WorkStream::run
template <int dim>
void Solid<dim>::update_qph_incremental()
{
FEValues<dim> fe_values (fe, qf_cell,
update_values | update_gradients);
FEValues<dim> fe_values_eta (fe_eta, qf_cell,
update_values | update_gradients);
std::vector<Tensor<2, dim> > solution_grads_total (qf_cell.size());
std::vector<double> solution_eta_total (qf_cell.size());
std::vector<double> old_solution_eta_total (qf_cell.size());
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler.begin_active(),
endc = dof_handler.end();
typename DoFHandler<dim>::active_cell_iterator
cell_eta = dof_handler_eta.begin_active();
for (; cell!=endc; ++cell, ++cell_eta)
if (cell->is_locally_owned())
{
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
Assert(lqph >= &quadrature_point_history.front(), ExcInternalError());
Assert(lqph <= &quadrature_point_history.back(), ExcInternalError());
Assert(solution_grads_total.size() == n_q_points,
ExcInternalError());
Assert(solution_eta_total.size() == n_q_points,
ExcInternalError());
fe_values.reinit(cell);
fe_values_eta.reinit (cell_eta);
fe_values[u_fe].get_function_gradients(solution, solution_grads_total);
fe_values_eta.get_function_values(solution_eta, solution_eta_total);
fe_values_eta.get_function_values(old_solution_eta, old_solution_eta_total);
for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
lqph[q_point].update_values(solution_grads_total[q_point],
solution_eta_total[q_point],
old_solution_eta_total[q_point],
parameters.thetan);
}
}
//////////////////////////////
template <int dim>
unsigned int
Solid<dim>::solve ()
{
LA::MPI::Vector
completely_distributed_solution (locally_owned_dofs, mpi_communicator);
SolverControl solver_control (dof_handler.n_dofs(), 1e-12*system_rhs.l2_norm());
#ifdef USE_PETSC_LA
LA::SolverCG solver(solver_control, mpi_communicator);
#else
LA::SolverCG solver(solver_control);
#endif
LA::MPI::PreconditionAMG preconditioner;
LA::MPI::PreconditionAMG::AdditionalData data;
#ifdef USE_PETSC_LA
data.symmetric_operator = true;
#else
/* Trilinos defaults are good */
#endif
preconditioner.initialize(tangent_matrix, data);
// LA::MPI::PreconditionSSOR preconditioner;
// preconditioner.initialize(tangent_matrix,1.2);
solver.solve (tangent_matrix, completely_distributed_solution, system_rhs,
preconditioner);
// PETScWrappers::SparseDirectMUMPS solver(solver_control, mpi_communicator);
// solver.solve (tangent_matrix, completely_distributed_solution, system_rhs);
constraints.distribute (completely_distributed_solution);
solution_update = completely_distributed_solution;
return solver_control.last_step();
}
///////////////////////////////////////////////////////////////////////////
template <int dim>
unsigned int
Solid<dim>::solve_eta ()
{
LA::MPI::Vector
completely_distributed_solution_eta (locally_owned_dofs_eta, mpi_communicator);
SolverControl solver_control (dof_handler_eta.n_dofs(), 1e-12*system_rhs_eta.l2_norm());
#ifdef USE_PETSC_LA
LA::SolverCG solver(solver_control, mpi_communicator);
#else
LA::SolverCG solver(solver_control);
#endif
LA::MPI::PreconditionAMG preconditioner;
LA::MPI::PreconditionAMG::AdditionalData data;
#ifdef USE_PETSC_LA
data.symmetric_operator = true;
#else
/* Trilinos defaults are good */
#endif
preconditioner.initialize(system_matrix_eta, data);
//LA::MPI::PreconditionJacobi preconditioner(system_matrix_eta);
solver.solve (system_matrix_eta, completely_distributed_solution_eta, system_rhs_eta,
preconditioner);
solution_update_eta = completely_distributed_solution_eta;
return solver_control.last_step();
}
///////////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::output_results() const
{
DataOut<dim> data_out;
std::vector<std::string> displacement_names;
switch (dim)
{
case 1:
displacement_names.push_back ("displacement");
break;
case 2:
displacement_names.push_back ("x_displacement");
displacement_names.push_back ("y_displacement");
break;
case 3:
displacement_names.push_back ("x_displacement");
displacement_names.push_back ("y_displacement");
displacement_names.push_back ("z_displacement");
break;
default:
Assert (false, ExcNotImplemented());
}
data_out.add_data_vector (dof_handler, solution, displacement_names);
data_out.add_data_vector (dof_handler_eta, solution_eta, "order_parameter");
/////////////////////////
Vector<double> norm_of_stress (triangulation.n_active_cells());
{
typename Triangulation<dim>::active_cell_iterator
cell = triangulation.begin_active(),
endc = triangulation.end();
for (; cell!=endc; ++cell)
if (cell->is_locally_owned())
{
SymmetricTensor<2,dim> accumulated_stress;
for (unsigned int q=0; q<qf_cell.size(); ++q)
accumulated_stress +=
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer())[q].get_tau();
norm_of_stress(cell->active_cell_index())
= (accumulated_stress /
qf_cell.size()).norm();
}
else
norm_of_stress(cell->active_cell_index()) = -1e+20;
}
data_out.add_data_vector (norm_of_stress, "norm_of_stress");
std::vector< std::vector< Vector<double> > >
history_field (dim, std::vector< Vector<double> >(dim)),
local_history_values_at_qpoints (dim, std::vector< Vector<double> >(dim)),
local_history_fe_values (dim, std::vector< Vector<double> >(dim)),
history_field_stress (dim, std::vector< Vector<double> >(dim)),
local_history_values_at_qpoints_stress (dim, std::vector< Vector<double> >(dim)),
local_history_fe_values_stress (dim, std::vector< Vector<double> >(dim));
for (unsigned int i=0; i<dim; i++)
for (unsigned int j=0; j<dim; j++)
{
history_field[i][j].reinit(history_dof_handler.n_dofs());
local_history_values_at_qpoints[i][j].reinit(qf_cell.size());
local_history_fe_values[i][j].reinit(history_fe.dofs_per_cell);
history_field_stress[i][j].reinit(history_dof_handler.n_dofs());
local_history_values_at_qpoints_stress[i][j].reinit(qf_cell.size());
local_history_fe_values_stress[i][j].reinit(history_fe.dofs_per_cell);
}
FullMatrix<double> qpoint_to_dof_matrix (history_fe.dofs_per_cell,
qf_cell.size());
FETools::compute_projection_from_quadrature_points_matrix
(history_fe,
qf_cell, qf_cell,
qpoint_to_dof_matrix);
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler.begin_active(),
endc = dof_handler.end(),
dg_cell = history_dof_handler.begin_active();
for (; cell!=endc; ++cell, ++dg_cell)
if (cell->is_locally_owned())
{
PointHistory<dim> *lqph
= reinterpret_cast<PointHistory<dim> *>(cell->user_pointer());
Assert (lqph >=
&quadrature_point_history.front(),
ExcInternalError());
Assert (lqph <
&quadrature_point_history.back(),
ExcInternalError());
for (unsigned int i=0; i<dim; i++)
for (unsigned int j=0; j<dim; j++)
{
for (unsigned int q=0; q<qf_cell.size(); ++q)
{
local_history_values_at_qpoints[i][j](q)
= lqph[q].get_F()[i][j];
qpoint_to_dof_matrix.vmult (local_history_fe_values[i][j],
local_history_values_at_qpoints[i][j]);
dg_cell->set_dof_values (local_history_fe_values[i][j],
history_field[i][j]);
local_history_values_at_qpoints_stress[i][j](q)
= lqph[q].get_tau()[i][j];
qpoint_to_dof_matrix.vmult (local_history_fe_values_stress[i][j],
local_history_values_at_qpoints_stress[i][j]);
dg_cell->set_dof_values (local_history_fe_values_stress[i][j],
history_field_stress[i][j]);
}
}
}
std::vector<DataComponentInterpretation::DataComponentInterpretation>
data_component_interpretation(1, DataComponentInterpretation::component_is_scalar);
data_out.add_data_vector(history_dof_handler, history_field[1][1], "F_22",
data_component_interpretation);
data_out.add_data_vector(history_dof_handler, history_field_stress[0][0], "sigma_11",
data_component_interpretation);
data_out.add_data_vector(history_dof_handler, history_field_stress[1][1], "sigma_22",
data_component_interpretation);
data_out.add_data_vector(history_dof_handler, history_field_stress[0][1], "sigma_12",
data_component_interpretation);
//////////////////////////
MappingQEulerian<dim, LA::MPI::Vector > q_mapping(degree, dof_handler, solution);
Vector<float> subdomain (triangulation.n_active_cells());
for (unsigned int i=0; i<subdomain.size(); ++i)
subdomain(i) = triangulation.locally_owned_subdomain();
data_out.add_data_vector (subdomain, "subdomain");
data_out.build_patches(q_mapping, degree);
const unsigned int cycle = time.get_timestep();
const std::string filename = ("solution-" +
Utilities::int_to_string (cycle, 2) +
"." +
Utilities::int_to_string
(triangulation.locally_owned_subdomain(), 4));
std::ofstream output ((filename + ".vtu").c_str());
data_out.write_vtu (output);
if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
{
std::vector<std::string> filenames;
for (unsigned int i=0;
i<Utilities::MPI::n_mpi_processes(mpi_communicator);
++i)
filenames.push_back ("solution-" +
Utilities::int_to_string (cycle, 2) +
"." +
Utilities::int_to_string (i, 4) +
".vtu");
std::ofstream master_output (("solution-" +
Utilities::int_to_string (cycle, 2) +
".pvtu").c_str());
data_out.write_pvtu_record (master_output, filenames);
}
}
}
/////////////////////////////////////////////////////////
int main (int argc, char *argv[])
{
try
{
using namespace dealii;
using namespace PhaseField;
//deallog.depth_console(0);
Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
Solid<3> solid_3d("parameters.prm");
solid_3d.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;
}
#include <deal.II/base/function.h>
#include <deal.II/base/parameter_handler.h>
#include <deal.II/base/point.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/symmetric_tensor.h>
#include <deal.II/base/tensor.h>
#include <deal.II/base/timer.h>
#include <deal.II/base/work_stream.h>
#include <deal.II/base/std_cxx11/shared_ptr.h>
#include <deal.II/base/logstream.h>
#include <deal.II/base/utilities.h>
#include <deal.II/dofs/dof_renumbering.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/grid/grid_in.h>
#include <deal.II/grid/tria.h>
#include <deal.II/grid/tria_boundary_lib.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/fe/fe_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/mapping_q_eulerian.h>
#include <deal.II/fe/mapping_q.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/constraint_matrix.h>
#include <deal.II/lac/compressed_sparsity_pattern.h>
#include <deal.II/lac/precondition_selector.h>
#include <deal.II/lac/sparse_direct.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/matrix_tools.h>
#include <iostream>
#include <fstream>
//////////////////////////////////////////////////////////////////
namespace PhaseField
{
using namespace dealii;
// INPUT OF PARAMETERS
namespace Parameters
{
struct FESystem
{
unsigned int poly_degree;
unsigned int quad_order;
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void FESystem::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Finite element system");
{
prm.declare_entry("Polynomial degree", "1",
Patterns::Integer(0),
"Displacement system polynomial order");
prm.declare_entry("Quadrature order", "2",
Patterns::Integer(0),
"Gauss quadrature order");
}
prm.leave_subsection();
}
void FESystem::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Finite element system");
{
poly_degree = prm.get_integer("Polynomial degree");
quad_order = prm.get_integer("Quadrature order");
}
prm.leave_subsection();
}
////////////////////////////////////////////////////
struct Geometry
{
unsigned int refinement;
double scale;
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void Geometry::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Geometry");
{
prm.declare_entry("Global refinement", "4",
Patterns::Integer(0),
"Global refinement level");
prm.declare_entry("Grid scale", "1e-9",
Patterns::Double(0.0),
"Global grid scaling factor");
}
prm.leave_subsection();
}
void Geometry::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Geometry");
{
refinement = prm.get_integer("Global refinement");
scale = prm.get_double("Grid scale");
}
prm.leave_subsection();
}
/////////////////////////////////////////////////
struct Materials
{
double lambda0; // austenite phase
double mu0; // austenite phase
double lambda1; // martensite phase
double mu1; // martensite phase
double L; // interface mobility
double beta; // gradient energy coefficient
double A0; // parameter for barrier height
double theta; // temperature
double thetac; // critical temperature
double thetae; // equilibrium temperature
double thetan; // Crank-Nicolson parameter
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void Materials::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Material properties");
{
prm.declare_entry("lambda austenite", "144.0e9", /* */
Patterns::Double(),
"lambda austenite");
prm.declare_entry("mu austenite", "74.0e9",
Patterns::Double(0.0),
"mu austenite");
prm.declare_entry("lambda martensite", "379.0e9",
Patterns::Double(),
"lambda martensite");
prm.declare_entry("mu martensite", "134.0e9",
Patterns::Double(0.0),
"mu martensite");
prm.declare_entry("kinetic coeff", "2600.0",
Patterns::Double(0.0),
"kinetic coeff");
prm.declare_entry("energy coeff", "2.59e-10",
Patterns::Double(0.0),
"energy coeff");
prm.declare_entry("barrier height", "28.0e6",
Patterns::Double(),
"barrier height");
prm.declare_entry("temperature", "50.0",
Patterns::Double(),
"temperature");
prm.declare_entry("temperature crit", "-183.0",
Patterns::Double(),
"temperature crit");
prm.declare_entry("temperature eql", "215.0",
Patterns::Double(),
"temperature eql");
prm.declare_entry("crank-nicolson parameter", "0.5",
Patterns::Double(),
"crank-nicolson parameter");
}
prm.leave_subsection();
}
void Materials::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Material properties");
{
lambda0 = prm.get_double("lambda austenite");
mu0 = prm.get_double("mu austenite");
lambda1 = prm.get_double("lambda martensite");
mu1 = prm.get_double("mu martensite");
L = prm.get_double("kinetic coeff");
beta = prm.get_double("energy coeff");
A0 = prm.get_double("barrier height");
theta = prm.get_double("temperature");
thetac = prm.get_double("temperature crit");
thetae = prm.get_double("temperature eql");
thetan = prm.get_double("crank-nicolson parameter");
}
prm.leave_subsection();
}
/////////////////////////////////////////////////
struct Time
{
double delta_t;
double end_time;
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
void Time::declare_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Time");
{
prm.declare_entry("End time", "5e-12",
Patterns::Double(),
"End time");
prm.declare_entry("Time step size", "1e-14",
Patterns::Double(),
"Time step size");
}
prm.leave_subsection();
}
void Time::parse_parameters(ParameterHandler &prm)
{
prm.enter_subsection("Time");
{
end_time = prm.get_double("End time");
delta_t = prm.get_double("Time step size");
}
prm.leave_subsection();
}
///////////////////////////////////////////////////////
struct AllParameters : public FESystem,
public Geometry,
public Materials,
public Time
{
AllParameters(const std::string &input_file);
static void
declare_parameters(ParameterHandler &prm);
void
parse_parameters(ParameterHandler &prm);
};
AllParameters::AllParameters(const std::string &input_file)
{
ParameterHandler prm;
declare_parameters(prm);
prm.read_input(input_file);
parse_parameters(prm);
}
void AllParameters::declare_parameters(ParameterHandler &prm)
{
FESystem::declare_parameters(prm);
Geometry::declare_parameters(prm);
Materials::declare_parameters(prm);
Time::declare_parameters(prm);
}
void AllParameters::parse_parameters(ParameterHandler &prm)
{
FESystem::parse_parameters(prm);
Geometry::parse_parameters(prm);
Materials::parse_parameters(prm);
Time::parse_parameters(prm);
}
}
// DEFINE SECOND ORDER IDENTITY, AND TWO FOURTH ORDER IDENTITY TENSORS
template <int dim>
class StandardTensors
{
public:
static const SymmetricTensor<2, dim> I;
static const SymmetricTensor<4, dim> IxI;
static const SymmetricTensor<4, dim> II;
// static const SymmetricTensor<2, dim> transformation_strain;
};
template <int dim>
const SymmetricTensor<2, dim>
StandardTensors<dim>::I = unit_symmetric_tensor<dim>();
template <int dim>
const SymmetricTensor<4, dim>
StandardTensors<dim>::IxI = outer_product(I, I);
template <int dim>
const SymmetricTensor<4, dim>
StandardTensors<dim>::II = identity_tensor<dim>();
// DEFINE TIME STEP, CURRENT TIME ETC.
class Time
{
public:
Time (const double time_end,
const double delta_t)
:
timestep(0),
time_current(0.0),
time_end(time_end),
delta_t(delta_t)
{}
virtual ~Time()
{}
double current() const
{
return time_current;
}
double end() const
{
return time_end;
}
double get_delta_t() const
{
return delta_t;
}
unsigned int get_timestep() const
{
return timestep;
}
void increment()
{
time_current += delta_t;
++timestep;
}
private:
unsigned int timestep;
double time_current;
const double time_end;
const double delta_t;
};
//////////////////////////////////////////////////////////
template <int dim>
class Material_Compressible_Neo_Hook_Three_Field
{
public:
Material_Compressible_Neo_Hook_Three_Field(const double lambda0,
const double mu0,
const double lambda1,
const double mu1,
const double A0,
const double theta,
const double thetac,
const double thetae)
:
det_F(1.0),
I1(0.0), // I1 = trace(Be)
ge(StandardTensors<dim>::I), // = Fe.Fe^T
Be(SymmetricTensor<2, dim>()), // = 0.5(Fe.Fe^T-I)
lambda00(lambda0),
mu00(mu0),
lambda11(lambda1),
mu11(mu1),
A00(A0),
theta1(theta),
thetac1(thetac),
thetae1(thetae)
{}
~Material_Compressible_Neo_Hook_Three_Field()
{}
void update_material_data (const Tensor<2, dim> &F, const Tensor<2, dim> &Fe,
const double phi, const double dphi,const double ddphi,
const double dPotentialBarrier, const double ddPotentialBarrier)
{
det_F = determinant(F); // determinant of total F
ge = symmetrize(Fe*transpose(Fe)); // ge = Fe.Fe^T
Be = 0.5*(ge-StandardTensors<dim>::I); // Be = 1/2(ge-I)
I1 = trace(Be); // first invariant of Be
lambda = lambda00+(lambda11-lambda00)*phi; // definition of the Lame constants are obvious
mu = mu00+(mu11-mu00)*phi;
deltaG = A00*(theta1-thetae1)/3.0; // difference in thermal energy
A = A00*(theta1-thetac1); // compute barrier height
dphi1 = dphi; // d_phi/d_eta
ddphi1 = ddphi;
dPotentialBarrier1 = dPotentialBarrier;
ddPotentialBarrier1 = ddPotentialBarrier;
Assert(det_F > 0, ExcInternalError());
}
SymmetricTensor<2, dim> get_tau() // tau is the Kirchhoff stress := J*Cauchy stress
{
return get_tau_kirchhoff();
}
SymmetricTensor<4, dim> get_Jc() const // comupte the fourth order modulus tensor in the deformed config.
{
return get_Jc_modulus();
}
double get_det_F() const
{
return det_F;
}
double get_driving_force_noStress() const // driving force excluding the transformational work
{
return get_driv_forc_noStress ();
}
double get_deri_driving_force_noStress() const // driving force excluding the transformational work
{
return get_deri_driv_forc_noStress ();
}
protected:
double det_F;
double I1;
SymmetricTensor<2, dim> ge;
SymmetricTensor<2, dim> Be;
double lambda00;
double mu00;
double lambda11;
double mu11;
double A00;
double theta1;
double thetac1;
double thetae1;
double lambda;
double mu;
double deltaG;
double A;
double dphi1;
double ddphi1;
double dPotentialBarrier1;
double ddPotentialBarrier1;
// compute the Kirchhoff stress
SymmetricTensor<2, dim> get_tau_kirchhoff() const
{
SymmetricTensor<2, dim> kirchhoff_stress = lambda*I1*ge +
mu*symmetrize(Tensor<2, dim>(ge) * Tensor<2, dim>(ge))-mu*ge;
return kirchhoff_stress;
}
// compute the modulus J*d_ijkl
SymmetricTensor<4, dim> get_Jc_modulus() const
{
SymmetricTensor<4,dim> elasticityTensor;
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)
elasticityTensor[i][j][k][l] =
lambda*ge[i][j]*ge[k][l]+mu*(ge[i][l]*ge[j][k]+ge[i][k]*ge[j][l]);
return elasticityTensor;
}
// compute the driving force excluding the transformational work
double get_driv_forc_noStress () const
{
return -A*dPotentialBarrier1-deltaG*dphi1;
}
double get_deri_driv_forc_noStress () const
{
return -A*ddPotentialBarrier1-deltaG*ddphi1;
}
};
// updates the quadrature point history
template <int dim>
class PointHistory
{
public:
PointHistory()
:
material(NULL),
F_inv(StandardTensors<dim>::I),
tau(SymmetricTensor<2, dim>()),
Jc(SymmetricTensor<4, dim>())
{}
virtual ~PointHistory()
{
delete material;
material = NULL;
}
void setup_lqp (const Parameters::AllParameters ¶meters)
{
material = new Material_Compressible_Neo_Hook_Three_Field<dim>(parameters.lambda0,
parameters.mu0, parameters.lambda1, parameters.mu1, parameters.A0,
parameters.theta, parameters.thetac, parameters.thetae);
update_values(Tensor<2, dim>(), double (), double (), double());
}
void update_values (const Tensor<2, dim> &Grad_u_n,
const double new_eta,
const double old_eta,
const double thetan)
{
double eta = thetan*new_eta +(1-thetan)*old_eta;
const Tensor<2, dim> F = (Tensor<2, dim>(StandardTensors<dim>::I) + Grad_u_n); // total F
const double phi = 3*eta*eta-2*eta*eta*eta; // interpolation function
const double dphi = 6*eta-6*eta*eta; // derivative of interpolation fn
const double ddphi = 6-12*eta;
const double dPotentialBarrier = 2*eta-6*eta*eta+4*eta*eta*eta;
const double ddPotentialBarrier =2-12*eta+12*eta*eta;
Tensor<2, dim> tmp; // transformation strain tensor
// double strectch1 = 0.8;
// double strectch2 = 1.2;
// tmp[0][0] = pow(strectch1, 1.5)/(1.0+strectch1) + pow(strectch2, 1.5)/(1.0+strectch2)-1.0;
// tmp[1][1] = pow(strectch1, 0.5)/(1.0+strectch1) + pow(strectch2, 0.5)/(1.0+strectch2)-1.0;
// tmp[2][2] = 0.0;
// tmp[0][1] = -strectch1/(1.0+strectch1) + strectch2/(1.0+strectch2);
// tmp[1][0] = -strectch1/(1.0+strectch1) + strectch2/(1.0+strectch2);
// tmp[0][2] = 0.0;
// tmp[2][0] = 0.0;
// tmp[1][2] = 0.0;
// tmp[2][1] = 0.0;
//
tmp[0][0] = 0.1;
tmp[1][1] = -0.05;
tmp[2][2] = -0.05;
tmp[0][1] = 0.0;
tmp[1][0] = 0.0;
tmp[0][2] = 0.0;
tmp[2][0] = 0.0;
tmp[1][2] = 0.0;
tmp[2][1] = 0.0;
SymmetricTensor<2, dim> transStrain = symmetrize(tmp);
const Tensor<2, dim> Ft = (Tensor<2, dim>(StandardTensors<dim>::I) +
Tensor<2, dim>(transStrain)*phi); // transformation deformation gradient
Fe = F * invert(Ft); // elastic part of deformation grad
material->update_material_data(F, Fe, phi, dphi, ddphi, dPotentialBarrier, ddPotentialBarrier);
F_inv = invert(F);
tau = material->get_tau(); // extracting kirchhoff stress
Jc = material->get_Jc(); // extracting J*d_ijkl
driving_force_noStress = material->get_driving_force_noStress(); // extracting driving force with no stress
deri_driving_force_noStress = material->get_deri_driving_force_noStress();
const Tensor<2, dim> temp_tensor = F_inv*Tensor<2, dim>(tau);
const Tensor<2, dim> temp_tensor1 = temp_tensor * Fe;
get_driv_forc = scalar_product(temp_tensor1, tmp)*dphi + driving_force_noStress; // computing total driving force
get_deri_driv_forc = scalar_product(temp_tensor1, tmp)*ddphi + deri_driving_force_noStress;
Assert(determinant(F_inv) > 0, ExcInternalError());
}
double get_det_F() const
{
return material->get_det_F();
}
const Tensor<2, dim> &get_F_inv() const
{
return F_inv;
}
const SymmetricTensor<2, dim> &get_tau() const
{
return tau;
}
const SymmetricTensor<4, dim> &get_Jc() const
{
return Jc;
}
double get_driving_force() const
{
return get_driv_forc;
}
double get_deri_driving_force() const
{
return get_deri_driv_forc;
}
private:
Material_Compressible_Neo_Hook_Three_Field<dim> *material;
Tensor<2, dim> F_inv;
SymmetricTensor<2, dim> tau;
SymmetricTensor<4, dim> Jc;
Tensor<2, dim> Fe;
double driving_force_noStress;
double deri_driving_force_noStress;
double dphi;
double ddphi;
double get_driv_forc;
double get_deri_driv_forc;
};
///////////////////////////////////////////////////////////////
template <int dim>
class Solid
{
public:
Solid(const std::string &input_file);
virtual
~Solid();
void
run();
private:
void make_grid();
void system_setup();
void assemble_system();
void solve_nonlinear_timestep();
unsigned int solve();
void make_constraints(const int &it_nr);
void assemble_system_eta();
void solve_nonlinear_timestep_eta();
unsigned int solve_eta();
void setup_qph();
void update_qph_incremental();
void output_results() const;
Parameters::AllParameters parameters;
double vol_reference; // volume of the reference config
double vol_current; // volume of the current config
Triangulation<dim> triangulation;
Time time; // variable of type class 'Time'
TimerOutput timer;
std::vector<PointHistory<dim> > quadrature_point_history;
const unsigned int degree; // degree of polynomial of shape functions
const FESystem<dim> fe; // fe object
DoFHandler<dim> dof_handler; // we have used two dof_handler: one for mechanics another for order parameter
const unsigned int dofs_per_cell; // no of dofs per cell for the mechanics problem
const FEValuesExtractors::Vector u_fe;
const QGauss<dim> qf_cell; // quadrature points in the cell
const QGauss<dim - 1> qf_face; // quadrature points at the face
const unsigned int n_q_points; // no of quadrature points in the cell
const unsigned int n_q_points_f; // no of quadrature points at the face
ConstraintMatrix constraints; // constraint object
SparsityPattern sparsity_pattern;
SparseMatrix<double> tangent_matrix; // tangent stiffenss matrix
Vector<double> system_rhs; // system right hand side or residual of mechanics problem
Vector<double> solution; // solution vector for displacement
Vector<double> solution_update; // another vector containing the displacement soln
const unsigned int degree_eta; // degree of polynomial for eta
FE_Q<dim> fe_eta; // fe object for eta
DoFHandler<dim> dof_handler_eta; //another dof_handler for eta
const unsigned int dofs_per_cell_eta; // dof per eta cell
const QGauss<dim> qf_cell_eta;
const unsigned int n_q_points_eta;
SparsityPattern sparsity_pattern_eta;
SparseMatrix<double> mass_matrix; // mass matrix out of Ginxburg-Landau eqn
SparseMatrix<double> laplace_matrix; // Laplace matrix out of Ginxburg-Landau eqn
SparseMatrix<double> system_matrix_eta;
SparseMatrix<double> nl_matrix;
Vector<double> nl_term;
Vector<double> system_rhs_eta;
Vector<double> solution_eta; // solution vector for eta
Vector<double> old_solution_eta;
Vector<double> solution_update_eta;
Vector<double> tmp_vector; // a vector used for solving eta
};
/////////////////////////////////////////////////////////
// defines the initial condition for the order parameter
template <int dim>
class InitialValues : public Function<dim>
{
public:
InitialValues () : Function<dim>() {}
virtual double value(const Point<dim> &p,
const unsigned int /*component = 0*/) const;
};
template <int dim>
double InitialValues<dim>::value (const Point<dim> &p,
const unsigned int /*component*/) const
{
//return 0.0;
// return 0.01;
return (rand()%100+0.0)*0.001;
// if ((p[0] > 2.5e-9) && (p[1] > 2.5e-9) && (p[0] < 7.5e-9) && (p[1] < 7.5e-9))
// return 1;
// else
// return 0;
////
// return
// -std::max(std::min(-tanh((sqrt((p[0]-3.0e-9)*(p[0]-3.0e-9)+(p[1]-3.0e-9)*(p[1]-3.0e-9))-1.0e-9)/0.4e-9),0.0),
// std::min(-tanh((sqrt((p[0]-7.0e-9)*(p[0]-7.0e-9)+(p[1]-3.0e-9)*(p[1]-3.0e-9))-1.0e-9)/0.4e-9),0.0));
// return std::max(tanh((2e-9-sqrt((p[0]-5.0e-9)*(p[0]-5.0e-9)+(p[1]-5.0e-9)*(p[1]-5.0e-9)))/0.4e-9),0.0);
//return (0.5*std::tanh(3.0*(p[0]-5.0e-9)/7.07e-10)+0.5);
// return 0.1 * std::max(tanh((p[0]-5.0e-9)/(0.4e-9)), 0.0);
// return 0.5*std::tanh(p[0]/(0.4e-9))+0.5;
}
/////////////////////////////////////////////////
template <int dim>
class BoundaryDisplacement : public Function<dim>
{
public:
BoundaryDisplacement (const int direction, const int time_step);
virtual
void
vector_value (const Point<dim> &p,
Vector<double> &values) const;
virtual
void
vector_value_list (const std::vector<Point<dim> > &points,
std::vector<Vector<double> > &value_list) const;
private:
const int direction;
const int time_step;
};
template <int dim>
BoundaryDisplacement<dim>::BoundaryDisplacement (const int direction,const int time_step)
:
Function<dim> (dim),
direction(direction),
time_step(time_step)
{}
template <int dim>
inline
void
BoundaryDisplacement<dim>::vector_value (const Point<dim> &/*p*/,
Vector<double> &values) const
{
Assert (values.size() == dim,
ExcDimensionMismatch (values.size(), dim));
values = 0;
if (time_step < 3)
values(direction) = 0.1e-9;
else
values(direction)= 0.001e-9;
}
template <int dim>
void
BoundaryDisplacement<dim>::vector_value_list (const std::vector<Point<dim> > &points,
std::vector<Vector<double> > &value_list) const
{
const unsigned int n_ooints = points.size();
Assert (value_list.size() == n_ooints,
ExcDimensionMismatch (value_list.size(), n_ooints));
for (unsigned int p=0; p<n_ooints; ++p)
BoundaryDisplacement<dim>::vector_value (points[p],
value_list[p]);
}
///////////////////////////////////////////////////
// constructor
template <int dim>
Solid<dim>::Solid(const std::string &input_file)
:
parameters(input_file),
triangulation(Triangulation<dim>::maximum_smoothing),
time(parameters.end_time, parameters.delta_t),
timer(std::cout,
TimerOutput::summary,
TimerOutput::wall_times),
degree(parameters.poly_degree),
fe(FE_Q<dim>(parameters.poly_degree), dim), // displacement
dof_handler(triangulation),
dofs_per_cell (fe.dofs_per_cell),
u_fe(0),
qf_cell(parameters.quad_order),
qf_face(parameters.quad_order),
n_q_points (qf_cell.size()),
n_q_points_f (qf_face.size()),
degree_eta(parameters.poly_degree),
fe_eta (parameters.poly_degree),
dof_handler_eta (triangulation),
dofs_per_cell_eta(fe_eta.dofs_per_cell),
qf_cell_eta(parameters.quad_order),
n_q_points_eta (qf_cell_eta.size())
{
// determine_component_extractor();
}
//destructor
template <int dim>
Solid<dim>::~Solid()
{
dof_handler.clear();
dof_handler_eta.clear();
}
///////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::make_grid()
{
// // Divide the beam, but only along the x- and y-coordinate directions
// std::vector< unsigned int > repetitions(dim, parameters.elements_per_edge);
// // Only allow one element through the thickness
// // (modelling a plane strain condition)
// if (dim == 3)
// repetitions[dim-1] = 1;
//
// const Point<dim> bottom_left = (dim == 3 ? Point<dim>(0.0, 0.0, -0.5) : Point<dim>(0.0, 0.0));
// const Point<dim> top_right = (dim == 3 ? Point<dim>(10.0, 10.0, 0.5) : Point<dim>(10.0, 10.0));
//
// GridGenerator::subdivided_hyper_rectangle(triangulation,
// repetitions,
// bottom_left,
// top_right,
// true);
GridGenerator::hyper_rectangle(triangulation,
Point<dim>(0.0, 0.0, 0.0),
Point<dim>(10.0, 10.0, 10.0),
true);
triangulation.refine_global (parameters.refinement);
GridTools::scale(parameters.scale, triangulation);
}
///////////////////////////////////////////////////
template <int dim>
void Solid<dim>::system_setup()
{
dof_handler.distribute_dofs(fe);
dof_handler_eta.distribute_dofs (fe_eta);
const unsigned int n_dofs = dof_handler.n_dofs(),
n_dofs_eta = dof_handler_eta.n_dofs();
std::cout << " Number of active cells: "
<< triangulation.n_active_cells()
<< std::endl
<< " Total number of cells: "
<< triangulation.n_cells()
<< std::endl
<< " Number of degrees of freedom: "
<< n_dofs + n_dofs_eta
<< " (" << n_dofs << '+' << n_dofs_eta << ')'
<< std::endl;
DynamicSparsityPattern dsp(dof_handler.n_dofs(),dof_handler.n_dofs());
DoFTools::make_sparsity_pattern (dof_handler, dsp );
sparsity_pattern.copy_from (dsp);
tangent_matrix.reinit(sparsity_pattern);
system_rhs.reinit(n_dofs);
solution.reinit(n_dofs);
solution_update.reinit(n_dofs);
DynamicSparsityPattern dsp_eta (n_dofs_eta, n_dofs_eta);
DoFTools::make_sparsity_pattern (dof_handler_eta, dsp_eta);
sparsity_pattern_eta.copy_from(dsp_eta);
mass_matrix.reinit (sparsity_pattern_eta);
laplace_matrix.reinit (sparsity_pattern_eta);
system_matrix_eta.reinit (sparsity_pattern_eta);
nl_matrix.reinit (sparsity_pattern_eta);
MatrixCreator::create_mass_matrix(dof_handler_eta,
QGauss<dim>(fe_eta.degree+1),
mass_matrix);
MatrixCreator::create_laplace_matrix(dof_handler_eta,
QGauss<dim>(fe_eta.degree+1),
laplace_matrix);
system_rhs_eta.reinit(n_dofs_eta);
nl_term.reinit(n_dofs_eta);
solution_eta.reinit(n_dofs_eta);
old_solution_eta.reinit(n_dofs_eta);
solution_update_eta.reinit(n_dofs_eta);
tmp_vector.reinit(n_dofs_eta);;
// sets up the quadrature point history
setup_qph();
}
////////////////////////////////
template <int dim>
void Solid<dim>::make_constraints(const int &it_nr)
{
if (it_nr > 1)
return;
constraints.clear();
const bool apply_dirichlet_bc = (it_nr == 0);
const int timestep = time.get_timestep();
const FEValuesExtractors::Scalar x_displacement(0);
const FEValuesExtractors::Scalar y_displacement(1);
const FEValuesExtractors::Scalar z_displacement(2);
{
const int boundary_id = 0;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(x_displacement) /*|
fe.component_mask(y_displacement) |
fe.component_mask(z_displacement)*/);
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(x_displacement)/* |
fe.component_mask(y_displacement) |
fe.component_mask(z_displacement)*/);
}
{
const int boundary_id = 1;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
BoundaryDisplacement<dim>(0, timestep),
constraints,
fe.component_mask(x_displacement));
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(x_displacement));
}
{
const int boundary_id = 2;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(y_displacement));
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(y_displacement));
}
//
// {
// const int boundary_id = 3;
//
// if (apply_dirichlet_bc == true)
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(y_displacement));
// else
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(y_displacement));
// }
{
const int boundary_id = 4;
if (apply_dirichlet_bc == true)
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(z_displacement));
else
VectorTools::interpolate_boundary_values(dof_handler,
boundary_id,
ZeroFunction<dim>(dim),
constraints,
fe.component_mask(z_displacement));
}
// {
// const int boundary_id = 5;
//
// if (apply_dirichlet_bc == true)
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(z_displacement));
// else
// VectorTools::interpolate_boundary_values(dof_handler,
// boundary_id,
// ZeroFunction<dim>(dim),
// constraints,
// fe.component_mask(z_displacement));
// }
// {
// const double tol_boundary = 0.7e-9;
// typename DoFHandler<dim>::active_cell_iterator
// cell = dof_handler.begin_active(),
// endc = dof_handler.end();
// for (; cell!=endc; ++cell)
// if (cell->is_locally_owned())
// {
// for (unsigned int v=0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
//
// if ((std::abs(cell->vertex(v)[0] - 0.0) < tol_boundary) &&
// (std::abs(cell->vertex(v)[1] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[2] - 5.0e-9) < tol_boundary))
// {
// constraints.add_line(cell->vertex_dof_index(v, 0));
// // constraints.add_line(cell->vertex_dof_index(v, 1));
// // constraints.add_line(cell->vertex_dof_index(v, 2));
// }
//
// else if ((std::abs(cell->vertex(v)[0] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[1] - 0.0) < tol_boundary) &&
// (std::abs(cell->vertex(v)[2] - 5.0e-9) < tol_boundary))
// {
// // constraints.add_line(cell->vertex_dof_index(v, 0));
// constraints.add_line(cell->vertex_dof_index(v, 1));
// //constraints.add_line(cell->vertex_dof_index(v, 2));
// }
//
// else if ((std::abs(cell->vertex(v)[0] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[1] - 5.0e-9) < tol_boundary) &&
// (std::abs(cell->vertex(v)[2] - 0) < tol_boundary))
// {
// //constraints.add_line(cell->vertex_dof_index(v, 0));
// //constraints.add_line(cell->vertex_dof_index(v, 1));
// constraints.add_line(cell->vertex_dof_index(v, 2));
// }
//
// }
// }
constraints.close();
}
/////////////////////////////////////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::assemble_system ()
{
tangent_matrix = 0;
system_rhs = 0;
FEValues<dim> fe_values (fe, qf_cell,
update_values | update_gradients |
update_quadrature_points | update_JxW_values);
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);
std::vector<double> Nx(dofs_per_cell);
std::vector<Tensor<2, dim> > grad_Nx(dofs_per_cell);
std::vector<SymmetricTensor<2, dim> > symm_grad_Nx(dofs_per_cell);
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler.begin_active(),
endc = dof_handler.end();
for (; cell!=endc; ++cell)
{
fe_values.reinit (cell);
cell_matrix = 0;
cell_rhs = 0;
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
{
const Tensor<2, dim> F_inv = lqph[q_point].get_F_inv();
const Tensor<2, dim> tau = lqph[q_point].get_tau();
const SymmetricTensor<2, dim> symm_tau = lqph[q_point].get_tau();
const SymmetricTensor<4, dim> Jc = lqph[q_point].get_Jc();
const double JxW = fe_values.JxW(q_point);
for (unsigned int k=0; k<dofs_per_cell; ++k)
{
grad_Nx[k] = fe_values[u_fe].gradient(k, q_point) * F_inv;
symm_grad_Nx[k] = symmetrize(grad_Nx[k]);
}
for (unsigned int i=0; i<dofs_per_cell; ++i)
{
const unsigned int component_i = fe.system_to_component_index(i).first;
for (unsigned int j=0; j<dofs_per_cell; ++j)
{
const unsigned int component_j = fe.system_to_component_index(j).first;
cell_matrix(i, j) += symm_grad_Nx[i] * Jc // The material contribution:
* symm_grad_Nx[j] * JxW;
if (component_i == component_j) // geometrical stress contribution
cell_matrix(i, j) += grad_Nx[i][component_i] * tau
* grad_Nx[j][component_j] * JxW;
}
cell_rhs(i) -= symm_grad_Nx[i] * symm_tau * JxW;
}
}
cell->get_dof_indices (local_dof_indices);
constraints.distribute_local_to_global(cell_matrix,
cell_rhs,
local_dof_indices,
tangent_matrix,
system_rhs);
}
}
//////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::assemble_system_eta ()
{
system_matrix_eta = 0;
system_rhs_eta = 0;
nl_matrix = 0;
nl_term = 0;
FEValues<dim> fe_values_eta (fe_eta, qf_cell_eta,
update_values | update_quadrature_points | update_JxW_values);
FullMatrix<double> cell_nl_matrix (dofs_per_cell_eta, dofs_per_cell_eta);
Vector <double> cell_nl_term (dofs_per_cell_eta);
std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell_eta);
std::vector<double> phi (dofs_per_cell_eta);
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler_eta.begin_active(),
endc = dof_handler_eta.end();
for (; cell!=endc; ++cell)
{
fe_values_eta.reinit(cell);
cell_nl_matrix = 0;
cell_nl_term = 0;
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
for (unsigned int q=0; q<n_q_points_eta; ++q)
{
const double driving_force = lqph[q].get_driving_force();
const double deri_driving_force = lqph[q].get_deri_driving_force();
for (unsigned int k=0; k<dofs_per_cell_eta; ++k)
{
phi[k] = fe_values_eta.shape_value (k, q);
}
for (unsigned int i=0; i<dofs_per_cell_eta; ++i)
{
for (unsigned int j=0; j<dofs_per_cell_eta; ++j)
{
cell_nl_matrix(i,j) += deri_driving_force * phi[i] * phi[j] * fe_values_eta.JxW(q);
}
cell_nl_term(i) += driving_force * phi[i] * fe_values_eta.JxW (q);
}
}
cell->get_dof_indices (local_dof_indices);
for (unsigned int i=0; i<dofs_per_cell_eta; ++i)
{
for (unsigned int j=0; j<dofs_per_cell_eta; ++j)
{
nl_matrix. add (local_dof_indices[i],
local_dof_indices[j],
cell_nl_matrix(i,j));
}
nl_term (local_dof_indices[i]) += cell_nl_term(i);
}
}
system_matrix_eta.copy_from (mass_matrix);
system_matrix_eta.add (parameters.L * parameters.beta * parameters.delta_t * parameters.thetan, laplace_matrix);
system_matrix_eta.add (-parameters.L * parameters.delta_t * parameters.thetan, nl_matrix);
SparseMatrix<double> tmp_matrix (sparsity_pattern_eta);
tmp_matrix.copy_from (mass_matrix);
tmp_matrix.add (parameters.L * parameters.beta * parameters.delta_t * parameters.thetan, laplace_matrix);
Vector<double> tmp_vector (solution_eta.size());
tmp_matrix.vmult (tmp_vector, solution_eta);
system_rhs_eta += tmp_vector;
tmp_matrix.add(-parameters.L * parameters.beta * parameters.delta_t , laplace_matrix);
tmp_matrix.vmult (tmp_vector, old_solution_eta);
system_rhs_eta -= tmp_vector;
system_rhs_eta.add (-parameters.L * parameters.delta_t, nl_term);
system_rhs_eta *= -1;
}
///////////////////////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::setup_qph()
{
{
triangulation.clear_user_data();
{
std::vector<PointHistory<dim> > tmp;
tmp.swap(quadrature_point_history);
}
quadrature_point_history
.resize(triangulation.n_active_cells() * n_q_points);
unsigned int history_index = 0;
for (typename Triangulation<dim>::active_cell_iterator
cell = triangulation.begin_active();
cell != triangulation.end(); ++cell)
{
cell->set_user_pointer(&quadrature_point_history[history_index]);
history_index += n_q_points;
}
Assert(history_index == quadrature_point_history.size(),
ExcInternalError());
}
for (typename Triangulation<dim>::active_cell_iterator
cell = triangulation.begin_active();
cell != triangulation.end(); ++cell)
{
PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
Assert(lqph >= &quadrature_point_history.front(), ExcInternalError());
Assert(lqph <= &quadrature_point_history.back(), ExcInternalError());
for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
lqph[q_point].setup_lqp(parameters);
}
}
// Updates the data at all quadrature points over a loop run by WorkStream::run
template <int dim>
void Solid<dim>::update_qph_incremental()
{
FEValues<dim> fe_values (fe, qf_cell,
update_values | update_gradients);
FEValues<dim> fe_values_eta (fe_eta, qf_cell,
update_values | update_gradients);
std::vector<Tensor<2, dim> > solution_grads_total (qf_cell.size());
std::vector<double> solution_eta_total (qf_cell.size());
std::vector<double> old_solution_eta_total (qf_cell.size());
typename DoFHandler<dim>::active_cell_iterator
cell = dof_handler.begin_active(),
endc = dof_handler.end();
typename DoFHandler<dim>::active_cell_iterator
cell_eta = dof_handler_eta.begin_active();
for (; cell!=endc; ++cell, ++cell_eta)
{ PointHistory<dim> *lqph =
reinterpret_cast<PointHistory<dim>*>(cell->user_pointer());
Assert(lqph >= &quadrature_point_history.front(), ExcInternalError());
Assert(lqph <= &quadrature_point_history.back(), ExcInternalError());
Assert(solution_grads_total.size() == n_q_points,
ExcInternalError());
Assert(solution_eta_total.size() == n_q_points,
ExcInternalError());
fe_values.reinit(cell);
fe_values_eta.reinit (cell_eta);
fe_values[u_fe].get_function_gradients(solution, solution_grads_total);
fe_values_eta.get_function_values(solution_eta, solution_eta_total);
fe_values_eta.get_function_values(old_solution_eta, old_solution_eta_total);
for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
lqph[q_point].update_values(solution_grads_total[q_point],
solution_eta_total[q_point],
old_solution_eta_total[q_point],
parameters.thetan);
}
}
///////////////////////////////////////////////////////////////////////////
template <int dim>
unsigned int
Solid<dim>::solve ()
{
SolverControl solver_control (1000, 1e-12*system_rhs.l2_norm());
SolverCG<> cg (solver_control);
PreconditionSSOR<> preconditioner;
preconditioner.initialize(tangent_matrix, 1.2);
cg.solve (tangent_matrix, solution_update,
system_rhs,
preconditioner);
constraints.distribute (solution_update);
return solver_control.last_step();
}
template <int dim>
unsigned int
Solid<dim>::solve_eta ()
{
SolverControl solver_control (1000, 1e-12*system_rhs_eta.l2_norm());
SolverCG<> cg (solver_control);
PreconditionSSOR<> preconditioner;
preconditioner.initialize(system_matrix_eta, 1.2);
cg.solve (system_matrix_eta, solution_update_eta,
system_rhs_eta,
preconditioner);
return solver_control.last_step();
}
///////////////////////////////////////////////////////////
template <int dim>
void Solid<dim>::output_results() const
{
std::vector<std::string> solution_name(dim, "displacement");
std::vector<DataComponentInterpretation::DataComponentInterpretation>
data_component_interpretation(dim,
DataComponentInterpretation::component_is_part_of_vector);
DataOut<dim> data_out;
data_out.attach_dof_handler(dof_handler);
data_out.add_data_vector(solution,
solution_name,
DataOut<dim>::type_dof_data,
data_component_interpretation);
data_out.add_data_vector (dof_handler_eta, solution_eta, "eta");
MappingQEulerian<dim> q_mapping(degree, dof_handler, solution);
data_out.build_patches(q_mapping, degree);
std::ostringstream filename;
filename << "solution-" << time.get_timestep() << ".vtk";
std::ofstream output(filename.str().c_str());
data_out.write_vtk(output);
}
//////////////////////////////////
template <int dim>
void Solid<dim>::solve_nonlinear_timestep()
{
double initial_rhs_norm = 0.;
unsigned int newton_iteration = 0;
for (; newton_iteration < 20; ++newton_iteration)
{
assemble_system ();
make_constraints(newton_iteration);
if (newton_iteration == 0)
initial_rhs_norm = system_rhs.l2_norm();
const unsigned int n_iterations
= solve ();
solution += solution_update;
update_qph_incremental();
if (newton_iteration == 0)
std::cout << " Solving for Displacement: " << n_iterations;
else
std::cout << '+' << n_iterations;
if (newton_iteration > 0 && system_rhs.l2_norm() <= 1e-6 * initial_rhs_norm)
{
std::cout << " CG iterations per nonlinear step. CONVERGED! " << std::endl;
break;
}
AssertThrow (newton_iteration < 19,
ExcMessage("No convergence in nonlinear solver!"));
}
}
/////////////////////////////////////////
template <int dim>
void Solid<dim>::solve_nonlinear_timestep_eta()
{
old_solution_eta = solution_eta;
double initial_rhs_norm = 0.;
unsigned int newton_iteration = 0;
for (; newton_iteration < 20; ++newton_iteration)
{
assemble_system_eta ();
if (newton_iteration == 0)
initial_rhs_norm = system_rhs_eta.l2_norm();
const unsigned int n_iterations
= solve_eta ();
solution_eta += solution_update_eta;
update_qph_incremental();
if (newton_iteration == 0)
std::cout << " Solving for Order Parameter: " << n_iterations;
else
std::cout << '+' << n_iterations;
if (newton_iteration > 0 && system_rhs_eta.l2_norm() <= 1e-6 * initial_rhs_norm)
{
std::cout << " CG iterations per nonlinear step. CONVERGED! " << std::endl;
break;
}
AssertThrow (newton_iteration < 19,
ExcMessage("No convergence in nonlinear solver!"));
}
}
//////////////////////////////////////////////////
template <int dim>
void Solid<dim>::run()
{
make_grid(); // generates the geometry and mesh
system_setup(); // sets up the system matrices
VectorTools::interpolate(dof_handler_eta, InitialValues<dim>(), solution_eta); //initial eta
old_solution_eta = solution_eta;
update_qph_incremental();
// this is the zeroth iteration for compute the initial distorted solution
//of the body due to arbitrary distribution of initial eta
solve_nonlinear_timestep();
output_results();
time.increment();
// computed actual time integration to update displacement and eta
while (time.current() <= time.end())
{
std::cout << std::endl
<< "Time step #" << time.get_timestep() << "; "
<< "advancing to t = " << time.current() << "."
<< std::endl;
solve_nonlinear_timestep_eta();
solve_nonlinear_timestep();
output_results();
time.increment();
}
}
}
/////////////////////////////////////////////////////////
int main ()
{
using namespace dealii;
using namespace PhaseField;
try
{
deallog.depth_console(0);
Solid<3> solid_3d("parameters.prm");
solid_3d.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;
}
parameters.prm
Description: Binary data
