Use bricks for solid meshes (demo_FEA_hexaANCF_3813.cpp)

Tutorial that teaches how to use the FEA module to perform FEA dynamics for bricks of ANCF type.

// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Alessandro Tasora
// =============================================================================
//
// FEA using the brick element
//
// =============================================================================
#include "chrono/physics/ChSystemSMC.h"
#include "chrono/fea/ChElementHexaANCF_3813.h"
#include "chrono/fea/ChElementBar.h"
#include "chrono/fea/ChLinkNodeFrame.h"
#include "chrono/fea/ChLinkNodeSlopeFrame.h"
#include "chrono/assets/ChVisualShapeFEA.h"
#include "chrono/solver/ChIterativeSolverLS.h"
#include "chrono_irrlicht/ChVisualSystemIrrlicht.h"
using namespace chrono;
using namespace chrono::fea;
using namespace chrono::irrlicht;
int main(int argc, char* argv[]) {
std::cout << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << std::endl;
std::cout << "-----------------------------------------------------------\n";
std::cout << "-----------------------------------------------------------\n";
std::cout << " Brick Elements demo with implicit integration \n";
std::cout << "-----------------------------------------------------------\n";
// The physical system: it contains all physical objects.
// Create a mesh, that is a container for groups
// of elements and their referenced nodes.
auto my_mesh = chrono_types::make_shared<ChMesh>();
// Geometry of the plate
double plate_lenght_x = 1;
double plate_lenght_y = 1;
double plate_lenght_z = 0.05; // small thickness
// Specification of the mesh
int numDiv_x = 4;
int numDiv_y = 4;
int numDiv_z = 1;
int N_x = numDiv_x + 1;
// Number of elements in the z direction is considered as 1
int TotalNumElements = numDiv_x * numDiv_y;
int TotalNumNodes = (numDiv_x + 1) * (numDiv_y + 1) * (numDiv_z + 1);
// For uniform mesh
double dx = plate_lenght_x / numDiv_x;
double dy = plate_lenght_y / numDiv_y;
double dz = plate_lenght_z / numDiv_z;
int MaxMNUM = 1;
int MaxLayNum = 1;
ChMatrixDynamic<double> COORDFlex(TotalNumNodes, 3);
ChMatrixDynamic<double> VELCYFlex(TotalNumNodes, 3);
ChMatrixDynamic<int> NumNodes(TotalNumElements, 8);
ChMatrixDynamic<int> LayNum(TotalNumElements, 1);
ChMatrixDynamic<int> NDR(TotalNumNodes, 3);
ChMatrixDynamic<double> ElemLengthXY(TotalNumElements, 3);
for (int i = 0; i < MaxMNUM; i++) {
MPROP(i, 0) = 500; // Density [kg/m3]
MPROP(i, 1) = 2.1E+05; // H(m)
MPROP(i, 2) = 0.3; // nu
}
auto mmaterial = chrono_types::make_shared<ChContinuumElastic>();
mmaterial->SetRayleighDampingBeta(0.0);
mmaterial->SetRayleighDampingAlpha(0.0);
mmaterial->SetDensity(MPROP(0, 0));
mmaterial->SetYoungModulus(MPROP(0, 1));
mmaterial->SetPoissonRatio(MPROP(0, 2));
for (int i = 0; i < TotalNumElements; i++) {
// All the elements belong to the same layer, e.g layer number 1.
LayNum(i, 0) = 1;
// Node number of the 4 nodes which creates element i.
// The nodes are distributed this way. First in the x direction for constant
// y when max x is reached go to the
// next level for y by doing the same distribution but for y+1 and keep
// doing until y limit is reached. Node
// number start from 1.
NumNodes(i, 0) = (i / (numDiv_x)) * (N_x) + i % numDiv_x;
NumNodes(i, 1) = (i / (numDiv_x)) * (N_x) + i % numDiv_x + 1;
NumNodes(i, 2) = (i / (numDiv_x)) * (N_x) + i % numDiv_x + 1 + N_x;
NumNodes(i, 3) = (i / (numDiv_x)) * (N_x) + i % numDiv_x + N_x;
NumNodes(i, 4) = (numDiv_x + 1) * (numDiv_y + 1) + NumNodes(i, 0);
NumNodes(i, 5) = (numDiv_x + 1) * (numDiv_y + 1) + NumNodes(i, 1);
NumNodes(i, 6) = (numDiv_x + 1) * (numDiv_y + 1) + NumNodes(i, 2);
NumNodes(i, 7) = (numDiv_x + 1) * (numDiv_y + 1) + NumNodes(i, 3);
// Let's keep the element length a fixed number in both direction. (uniform
// distribution of nodes in both direction)
ElemLengthXY(i, 0) = dx;
ElemLengthXY(i, 1) = dy;
ElemLengthXY(i, 2) = dz;
if (MaxLayNum < LayNum(i, 0)) {
MaxLayNum = LayNum(i, 0);
}
}
for (int i = 0; i < TotalNumNodes; i++) {
// If the node is the first node from the left side fix the x,y,z degree of
// freedom. 1 for constrained 0 for ...
//-The NDR array is used to define the degree of freedoms that are
// constrained in the 6 variable explained above.
NDR(i, 0) = (i % (numDiv_x + 1) == 0) ? 1 : 0;
NDR(i, 1) = (i % (numDiv_x + 1) == 0) ? 1 : 0;
NDR(i, 2) = (i % (numDiv_x + 1) == 0) ? 1 : 0;
//-COORDFlex are the initial coordinates for each node,
// the first three are the position
COORDFlex(i, 0) = (i % (numDiv_x + 1)) * dx;
COORDFlex(i, 1) = (i / (numDiv_x + 1)) % (numDiv_y + 1) * dy;
COORDFlex(i, 2) = (i) / ((numDiv_x + 1) * (numDiv_y + 1)) * dz;
//-VELCYFlex is essentially the same as COORDFlex, but for the initial
// velocity instead of position.
// let's assume zero initial velocity for nodes
VELCYFlex(i, 0) = 0;
VELCYFlex(i, 1) = 0;
VELCYFlex(i, 2) = 0;
}
// Adding the nodes to the mesh
int i = 0;
while (i < TotalNumNodes) {
auto node =
chrono_types::make_shared<ChNodeFEAxyz>(ChVector3d(COORDFlex(i, 0), COORDFlex(i, 1), COORDFlex(i, 2)));
node->SetMass(0.0);
my_mesh->AddNode(node);
if (NDR(i, 0) == 1 && NDR(i, 1) == 1 && NDR(i, 2) == 1) {
node->SetFixed(true);
}
i++;
}
auto nodetip = std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(TotalNumNodes - 1));
int elemcount = 0;
while (elemcount < TotalNumElements) {
auto element = chrono_types::make_shared<ChElementHexaANCF_3813>();
ChVector3d InertFlexVec(ElemLengthXY(elemcount, 0), ElemLengthXY(elemcount, 1),
ElemLengthXY(elemcount, 2)); // read element length, used in ChElementHexaANCF_3813
element->SetInertFlexVec(InertFlexVec);
element->SetNodes(std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 0))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 1))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 2))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 3))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 4))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 5))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 6))),
std::dynamic_pointer_cast<ChNodeFEAxyz>(my_mesh->GetNode(NumNodes(elemcount, 7))));
element->SetMaterial(mmaterial);
element->SetElemNum(elemcount); // for EAS
element->SetMooneyRivlin(false); // turn on/off Mooney Rivlin (Linear Isotropic by default)
ChVectorN<double, 9> stock_alpha_EAS; //
stock_alpha_EAS.setZero();
element->SetStockAlpha(stock_alpha_EAS(0), stock_alpha_EAS(1), stock_alpha_EAS(2), stock_alpha_EAS(3),
stock_alpha_EAS(4), stock_alpha_EAS(5), stock_alpha_EAS(6), stock_alpha_EAS(7),
stock_alpha_EAS(8));
my_mesh->AddElement(element);
elemcount++;
}
// Remember to add the mesh to the system!
sys.Add(my_mesh);
// Options for visualization in irrlicht
auto mvisualizemesh = chrono_types::make_shared<ChVisualShapeFEA>(my_mesh);
mvisualizemesh->SetFEMdataType(ChVisualShapeFEA::DataType::NODE_FIELD_VALUE);
mvisualizemesh->SetShrinkElements(true, 0.85);
mvisualizemesh->SetSmoothFaces(false);
my_mesh->AddVisualShapeFEA(mvisualizemesh);
auto mvisualizemeshref = chrono_types::make_shared<ChVisualShapeFEA>(my_mesh);
mvisualizemeshref->SetFEMdataType(ChVisualShapeFEA::DataType::SURFACE);
mvisualizemeshref->SetWireframe(true);
mvisualizemeshref->SetDrawInUndeformedReference(true);
my_mesh->AddVisualShapeFEA(mvisualizemeshref);
auto mvisualizemeshC = chrono_types::make_shared<ChVisualShapeFEA>(my_mesh);
mvisualizemeshC->SetFEMglyphType(ChVisualShapeFEA::GlyphType::NODE_DOT_POS);
mvisualizemeshC->SetFEMdataType(ChVisualShapeFEA::DataType::SURFACE);
mvisualizemeshC->SetSymbolsThickness(0.015);
my_mesh->AddVisualShapeFEA(mvisualizemeshC);
auto mvisualizemeshD = chrono_types::make_shared<ChVisualShapeFEA>(my_mesh);
mvisualizemeshD->SetFEMglyphType(ChVisualShapeFEA::GlyphType::NONE);
mvisualizemeshD->SetFEMdataType(ChVisualShapeFEA::DataType::SURFACE);
mvisualizemeshD->SetSymbolsScale(1);
mvisualizemeshD->SetColorscaleMinMax(-0.5, 5);
mvisualizemeshD->SetZbufferHide(false);
my_mesh->AddVisualShapeFEA(mvisualizemeshD);
// Create the Irrlicht visualization system
auto vis = chrono_types::make_shared<ChVisualSystemIrrlicht>();
vis->SetWindowSize(800, 600);
vis->SetWindowTitle("Brick Elements");
vis->Initialize();
vis->AddLogo();
vis->AddSkyBox();
vis->AddTypicalLights();
vis->AddCamera(ChVector3d(1.7, 1.0, -1.7), ChVector3d(0.2, 0.2, 0.0));
vis->AttachSystem(&sys);
// Perform a dynamic time integration:
auto solver = chrono_types::make_shared<ChSolverMINRES>();
sys.SetSolver(solver);
solver->SetMaxIterations(1000);
solver->SetTolerance(1e-10);
solver->EnableDiagonalPreconditioner(true);
solver->SetVerbose(false);
sys.SetTimestepperType(ChTimestepper::Type::HHT);
auto mystepper = std::dynamic_pointer_cast<ChTimestepperHHT>(sys.GetTimestepper());
mystepper->SetAlpha(-0.2);
mystepper->SetMaxIters(100);
mystepper->SetAbsTolerances(1e-3);
while (vis->Run()) {
vis->BeginScene();
vis->Render();
vis->EndScene();
sys.DoStepDynamics(0.004);
}
return 0;
}
Eigen::Matrix< T, N, 1 > ChVectorN
Column vector with fixed size (known at compile time).
Definition: ChMatrix.h:122
void Add(std::shared_ptr< ChPhysicsItem > item)
Attach an arbitrary ChPhysicsItem (e.g.
Definition: ChSystem.cpp:196
std::shared_ptr< ChTimestepper > GetTimestepper() const
Get the timestepper currently used for time integration.
Definition: ChSystem.h:93
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > ChMatrixDynamic
Dense matrix with dynamic size (i.e., with unknown at compile time) and row-major storage.
Definition: ChMatrix.h:75
Namespace with classes for the Irrlicht module.
Definition: ChApiIrr.h:47
void SetGravitationalAcceleration(const ChVector3d &gacc)
Set the gravitational acceleration vector.
Definition: ChSystem.h:148
int DoStepDynamics(double step_size)
Advance the dynamics simulation by a single time step of given length.
Definition: ChSystem.cpp:1632
Class for a physical system in which contact is modeled using a smooth (penalty-based) method.
Definition: ChSystemSMC.h:30
ChVector3< double > ChVector3d
Alias for double-precision vectors.
Definition: ChVector3.h:283
virtual void SetSolver(std::shared_ptr< ChSolver > newsolver)
Attach a solver (derived from ChSolver) for use by this system.
Definition: ChSystem.cpp:319
Main namespace for the Chrono package.
Definition: ChCamera.cpp:17
void SetTimestepperType(ChTimestepper::Type type)
Set the method for time integration (time stepper type).
Definition: ChSystem.cpp:412
Namespace for FEA classes.
Definition: ChVisualShapeFEA.h:28
Eigen::Matrix< T, M, N, Eigen::RowMajor > ChMatrixNM
Dense matrix with fixed size (known at compile time) and row-major storage.
Definition: ChMatrix.h:80