void SolidMechanicsBCHandling::user_apply_neumann_bcs( AssemblyContext& context, const GRINS::CachedValues& /*cache*/, const bool /*request_jacobian*/, const BoundaryID bc_id, const BCType bc_type ) const { switch( bc_type ) { case(CONSTANT_TRACTION): { const libMesh::Point& traction = this->get_neumann_bc_value(bc_id); _bound_conds.apply_neumann_normal( context, _disp_vars.u_var(), 1.0, traction(0) ); if( _disp_vars.have_v() ) _bound_conds.apply_neumann_normal( context, _disp_vars.v_var(), 1.0, traction(1) ); if( _disp_vars.have_w() ) _bound_conds.apply_neumann_normal( context, _disp_vars.w_var(), 1.0, traction(2) ); } break; default: { std::cerr << "Error: Invalid Neumann BC type for " << _physics_name << std::endl; libmesh_error(); } } // switch( bc_type ) return; }
// Update the coefficients associated with the patch field void timeVaryingSolidTractionFvPatchVectorField::updateCoeffs() { if (updated()) { return; } traction() = timeSeries_(this->db().time().timeOutputValue()); solidTractionFvPatchVectorField::updateCoeffs(); }
void ContinuumMechanicsNeumannBcsAssembler<DIM>::AssembleOnBoundaryElement(BoundaryElement<DIM-1,DIM>& rBoundaryElement, c_vector<double,STENCIL_SIZE>& rBelem, unsigned boundaryConditionIndex) { rBelem.clear(); c_vector<double, DIM> weighted_direction; double jacobian_determinant; mpMesh->GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant); c_vector<double,NUM_NODES_PER_ELEMENT> phi; for (unsigned quad_index=0; quad_index<mpQuadRule->GetNumQuadPoints(); quad_index++) { double wJ = jacobian_determinant * mpQuadRule->GetWeight(quad_index); const ChastePoint<DIM-1>& quad_point = mpQuadRule->rGetQuadPoint(quad_index); QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quad_point, phi); c_vector<double,DIM> traction = zero_vector<double>(DIM); switch (mpProblemDefinition->GetTractionBoundaryConditionType()) { case ELEMENTWISE_TRACTION: { traction = mpProblemDefinition->rGetElementwiseTractions()[boundaryConditionIndex]; break; } default: // Functional traction not implemented yet.. NEVER_REACHED; } for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++) { unsigned spatial_dim = index%DIM; unsigned node_index = (index-spatial_dim)/DIM; assert(node_index < NUM_NODES_PER_ELEMENT); rBelem(index) += traction(spatial_dim) * phi(node_index) * wJ; } } }
timeVaryingSolidTractionFvPatchVectorField:: timeVaryingSolidTractionFvPatchVectorField ( const fvPatch& p, const DimensionedField<vector, volMesh>& iF, const dictionary& dict ) : solidTractionFvPatchVectorField(p, iF), timeSeries_(dict) { fieldName() = dimensionedInternalField().name(); traction() = vector::zero; pressure() = 0.0; nonLinear() = nonLinearGeometry::nonLinearNames_.read(dict.lookup("nonLinear")); //- the leastSquares has zero non-orthogonal correction //- on the boundary //- so the gradient scheme should be extendedLeastSquares if ( Foam::word ( dimensionedInternalField().mesh().schemesDict().gradScheme ( "grad(" + fieldName() + ")" ) ) != "extendedLeastSquares" ) { Warning << "The gradScheme for " << fieldName() << " should be \"extendedLeastSquares 0\" for the boundary " << "non-orthogonal correction to be right" << endl; } }
/* == Mechano-electric feedback, and alternative boundary conditions == * * Let us now run a simulation with mechano-electric feedback (MEF), and with different boundary conditions. */ void TestWithMef() throw(Exception) { /* If we want to use MEF, where the stretch (in the fibre-direction) couples back to the cell * model and is used in stretch-activated channels (SACs), we can't just let Chaste convert * from cellml to C++ code as usual (see electro-physiology tutorials on how cell model files * are autogenerated from CellML during compilation), since these files don't use stretch and don't * have SACs. We have to use pycml to create a cell model class for us, rename and save it, and * manually add the SAC current. * * There is one example of this already in the code-base, which we will use it the following * simulation. It is the Noble 98 model, with a SAC added that depends linearly on stretches (>1). * It is found in the file !NobleVargheseKohlNoble1998WithSac.hpp, and is called * `CML_noble_varghese_kohl_noble_1998_basic_with_sac`. * * To add a SAC current to (or otherwise alter) your favourite cell model, you have to do the following. * Auto-generate the C++ code, by running the following on the cellml file: * `./python/ConvertCellModel.py heart/src/odes/cellml/LuoRudy1991.cellml` * (see [wiki:ChasteGuides/CodeGenerationFromCellML#Usingthehelperscript ChasteGuides/CodeGenerationFromCellML#Usingthehelperscript] * if you want further documentation on this script). * * Copy and rename the resultant .hpp and .cpp files (which can be found in the same folder as the * input cellml). For example, rename everything to `LuoRudy1991WithSac`. Then alter the class * to overload the method `AbstractCardiacCell::SetStretch(double stretch)` to store the stretch, * and then implement the SAC in the `GetIIonic()` method. `CML_noble_varghese_kohl_noble_1998_basic_with_sac` * provides an example of the changes that need to be made. * * Let us create a cell factory returning these Noble98 SAC cells, but with no stimulus - the * SAC switching on will lead be to activation. */ ZeroStimulusCellFactory<CML_noble_varghese_kohl_noble_1998_basic_with_sac, 2> cell_factory; /* Construct two meshes are before, in 2D */ TetrahedralMesh<2,2> electrics_mesh; electrics_mesh.ConstructRegularSlabMesh(0.01/*stepsize*/, 0.1/*length*/, 0.1/*width*/, 0.1/*depth*/); QuadraticMesh<2> mechanics_mesh; mechanics_mesh.ConstructRegularSlabMesh(0.02, 0.1, 0.1, 0.1 /*as above with a different stepsize*/); /* Collect the fixed nodes. This time we directly specify the new locations. We say the * nodes on X=0 are to be fixed, setting the deformed x=0, but leaving y to be free * (sliding boundary conditions). This functionality is described in more detail in the * solid mechanics tutorials. */ std::vector<unsigned> fixed_nodes; std::vector<c_vector<double,2> > fixed_node_locations; fixed_nodes.push_back(0); fixed_node_locations.push_back(zero_vector<double>(2)); for(unsigned i=1; i<mechanics_mesh.GetNumNodes(); i++) { double X = mechanics_mesh.GetNode(i)->rGetLocation()[0]; if(fabs(X) < 1e-6) // ie, if X==0 { c_vector<double,2> new_position; new_position(0) = 0.0; new_position(1) = ElectroMechanicsProblemDefinition<2>::FREE; fixed_nodes.push_back(i); fixed_node_locations.push_back(new_position); } } /* Now specify tractions on the top and bottom surfaces. For full descriptions of how * to apply tractions see the solid mechanics tutorials. Here, we collect the boundary * elements on the bottom and top surfaces, and apply inward tractions - this will have the * effect of stretching the tissue in the X-direction. */ std::vector<BoundaryElement<1,2>*> boundary_elems; std::vector<c_vector<double,2> > tractions; c_vector<double,2> traction; for (TetrahedralMesh<2,2>::BoundaryElementIterator iter = mechanics_mesh.GetBoundaryElementIteratorBegin(); iter != mechanics_mesh.GetBoundaryElementIteratorEnd(); ++iter) { if (fabs((*iter)->CalculateCentroid()[1] - 0.0) < 1e-6) // if Y=0 { BoundaryElement<1,2>* p_element = *iter; boundary_elems.push_back(p_element); traction(0) = 0.0; // kPa, since the contraction model and material law use kPa for stiffnesses traction(1) = 1.0; // kPa, since the contraction model and material law use kPa for stiffnesses tractions.push_back(traction); } if (fabs((*iter)->CalculateCentroid()[1] - 0.1) < 1e-6) // if Y=0.1 { BoundaryElement<1,2>* p_element = *iter; boundary_elems.push_back(p_element); traction(0) = 0.0; traction(1) = -1.0; tractions.push_back(traction); } } /* Now set up the problem. We will use a compressible approach. */ ElectroMechanicsProblemDefinition<2> problem_defn(mechanics_mesh); problem_defn.SetContractionModel(KERCHOFFS2003,0.01/*contraction model ODE timestep*/); problem_defn.SetUseDefaultCardiacMaterialLaw(INCOMPRESSIBLE); problem_defn.SetMechanicsSolveTimestep(1.0); /* Set the fixed node and traction info. */ problem_defn.SetFixedNodes(fixed_nodes, fixed_node_locations); problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions); /* Now say that the deformation should affect the electro-physiology */ problem_defn.SetDeformationAffectsElectrophysiology(false /*deformation affects conductivity*/, true /*deformation affects cell models*/); /* Set the end time, create the problem, and solve */ HeartConfig::Instance()->SetSimulationDuration(50.0); CardiacElectroMechanicsProblem<2,1> problem(INCOMPRESSIBLE, MONODOMAIN, &electrics_mesh, &mechanics_mesh, &cell_factory, &problem_defn, "TestCardiacElectroMechanicsWithMef"); problem.Solve(); /* Nothing exciting happens in the simulation as it is currently written. To get some interesting occurring, * alter the SAC conductance in the cell model from 0.035 to 0.35 (micro-Siemens). * (look for the line `const double g_sac = 0.035` in `NobleVargheseKohlNoble1998WithSac.hpp`). * * Rerun and visualise as usual, using Cmgui. By visualising the voltage on the deforming mesh, you can see that the * voltage gradually increases due to the SAC, since the tissue is stretched, until the threshold is reached * and activation occurs. * * For MEF simulations, we may want to visualise the electrical results on the electrics mesh using * Meshalyzer, for example to more easily visualise action potentials. This isn't (and currently * can't be) created by `CardiacElectroMechanicsProblem`. We can use a converter as follows * to post-process: */ FileFinder test_output_folder("TestCardiacElectroMechanicsWithMef/electrics", RelativeTo::ChasteTestOutput); Hdf5ToMeshalyzerConverter<2,2> converter(test_output_folder, "voltage", &electrics_mesh, false, HeartConfig::Instance()->GetVisualizerOutputPrecision()); /* Some other notes. If you want to apply time-dependent traction boundary conditions, this is possible by * specifying the traction in functional form - see solid mechanics tutorials. Similarly, more natural * 'pressure acting on the deformed body' boundary conditions are possible - see below tutorial. * * '''Robustness:''' Sometimes the nonlinear solver doesn't converge, and will give an error. This can be due to either * a non-physical (or not very physical) situation, or just because the current guess is quite far * from the solution and the solver can't find the solution (this can occur in nonlinear elasticity * problems if the loading is large, for example). Current work in progress is on making the solver * more robust, and also on parallelising the solver. One option when a solve fails is to decrease the * mechanics timestep. */ /* Ignore the following, it is just to check nothing has changed. */ Hdf5DataReader reader("TestCardiacElectroMechanicsWithMef/electrics", "voltage"); unsigned num_timesteps = reader.GetUnlimitedDimensionValues().size(); Vec voltage = PetscTools::CreateVec(electrics_mesh.GetNumNodes()); reader.GetVariableOverNodes(voltage, "V", num_timesteps-1); ReplicatableVector voltage_repl(voltage); for(unsigned i=0; i<voltage_repl.GetSize(); i++) { TS_ASSERT_DELTA(voltage_repl[i], -81.9080, 1e-3); } PetscTools::Destroy(voltage); }
/* This function is used in the first test */ c_vector<double,2> MyTraction(c_vector<double,2>& rX, double time) { c_vector<double,2> traction = zero_vector<double>(2); traction(0) = rX(0); return traction; }
void TestAssembler2d() throw (Exception) { QuadraticMesh<2> mesh; TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/canonical_triangle_quadratic", 2, 2, false); mesh.ConstructFromMeshReader(mesh_reader); ContinuumMechanicsProblemDefinition<2> problem_defn(mesh); double t1 = 2.6854233; double t2 = 3.2574578; // for the boundary element on the y=0 surface, create a traction std::vector<BoundaryElement<1,2>*> boundary_elems; std::vector<c_vector<double,2> > tractions; c_vector<double,2> traction; traction(0) = t1; traction(1) = t2; for (TetrahedralMesh<2,2>::BoundaryElementIterator iter = mesh.GetBoundaryElementIteratorBegin(); iter != mesh.GetBoundaryElementIteratorEnd(); ++iter) { if (fabs((*iter)->CalculateCentroid()[1])<1e-4) { BoundaryElement<1,2>* p_element = *iter; boundary_elems.push_back(p_element); tractions.push_back(traction); } } assert(boundary_elems.size()==1); problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions); ContinuumMechanicsNeumannBcsAssembler<2> assembler(&mesh, &problem_defn); TS_ASSERT_THROWS_THIS(assembler.AssembleVector(), "Vector to be assembled has not been set"); Vec bad_sized_vec = PetscTools::CreateVec(2); assembler.SetVectorToAssemble(bad_sized_vec, true); TS_ASSERT_THROWS_THIS(assembler.AssembleVector(), "Vector provided to be assembled has size 2, not expected size of 18 ((dim+1)*num_nodes)"); Vec vec = PetscTools::CreateVec(3*mesh.GetNumNodes()); assembler.SetVectorToAssemble(vec, true); assembler.AssembleVector(); ReplicatableVector vec_repl(vec); // Note: on a 1d boundary element, intgl phi_i dx = 1/6 for the bases on the vertices // and intgl phi_i dx = 4/6 for the basis at the interior node. (Here the integrals // are over the canonical 1d element, [0,1], which is also the physical element for this // mesh. // node 0 is on the surface, and is a vertex TS_ASSERT_DELTA(vec_repl[0], t1/6.0, 1e-8); TS_ASSERT_DELTA(vec_repl[1], t2/6.0, 1e-8); // node 1 is on the surface, and is a vertex TS_ASSERT_DELTA(vec_repl[3], t1/6.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4], t2/6.0, 1e-8); // nodes 2, 3, 4 are not on the surface for(unsigned i=2; i<5; i++) { TS_ASSERT_DELTA(vec_repl[3*i], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[3*i], 0.0, 1e-8); } // node 5 is on the surface, and is an interior node TS_ASSERT_DELTA(vec_repl[15], 4*t1/6.0, 1e-8); TS_ASSERT_DELTA(vec_repl[16], 4*t2/6.0, 1e-8); // the rest of the vector is the pressure block and should be zero. TS_ASSERT_DELTA(vec_repl[2], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[5], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[8], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[11], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[14], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[17], 0.0, 1e-8); PetscTools::Destroy(vec); PetscTools::Destroy(bad_sized_vec); }
void TestAssembler3d() throw (Exception) { QuadraticMesh<3> mesh(1.0, 1.0, 1.0, 1.0); ContinuumMechanicsProblemDefinition<3> problem_defn(mesh); double t1 = 2.6854233; double t2 = 3.2574578; double t3 = 4.5342308; // for the boundary element on the z=0 surface, create a traction std::vector<BoundaryElement<2,3>*> boundary_elems; std::vector<c_vector<double,3> > tractions; c_vector<double,3> traction; traction(0) = t1; traction(1) = t2; traction(2) = t3; for (TetrahedralMesh<3,3>::BoundaryElementIterator iter = mesh.GetBoundaryElementIteratorBegin(); iter != mesh.GetBoundaryElementIteratorEnd(); ++iter) { if (fabs((*iter)->CalculateCentroid()[2])<1e-4) { BoundaryElement<2,3>* p_element = *iter; boundary_elems.push_back(p_element); tractions.push_back(traction); } } assert(boundary_elems.size()==2); problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions); Vec vec = PetscTools::CreateVec(4*mesh.GetNumNodes()); ContinuumMechanicsNeumannBcsAssembler<3> assembler(&mesh, &problem_defn); assembler.SetVectorToAssemble(vec, true); assembler.AssembleVector(); ReplicatableVector vec_repl(vec); // For boundary elements in 3d - ie for 2d elements - and with QUADRATIC basis functions, we have // \intgl_{canonical element} \phi_i dV = 0.0 for i=0,1,2 (ie bases on vertices) // and // \intgl_{canonical element} \phi_i dV = 1/6 for i=3,4,5 (ie bases on mid-nodes) for(unsigned i=0; i<mesh.GetNumNodes(); i++) { double x = mesh.GetNode(i)->rGetLocation()[0]; double y = mesh.GetNode(i)->rGetLocation()[1]; double z = mesh.GetNode(i)->rGetLocation()[2]; if(fabs(z)<1e-8) // ie if z=0 { if( fabs(x-0.5)<1e-8 || fabs(y-0.5)<1e-8 ) // if x=0.5 or y=0.5 { unsigned num_surf_elems_contained_in = 1; if( fabs(x+y-1.0)<1e-8 ) // if x=0.5 AND y=0.5 { num_surf_elems_contained_in = 2; } // interior node on traction surface TS_ASSERT_DELTA(vec_repl[4*i], num_surf_elems_contained_in * t1/6.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4*i+1], num_surf_elems_contained_in * t2/6.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4*i+2], num_surf_elems_contained_in * t3/6.0, 1e-8); } else { TS_ASSERT_DELTA(vec_repl[4*i], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4*i+1], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4*i+2], 0.0, 1e-8); } } else { TS_ASSERT_DELTA(vec_repl[4*i], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4*i+1], 0.0, 1e-8); TS_ASSERT_DELTA(vec_repl[4*i+2], 0.0, 1e-8); } } for(unsigned i=0; i<mesh.GetNumNodes(); i++) { TS_ASSERT_DELTA(vec_repl[4*i+3], 0.0, 1e-8); } PetscTools::Destroy(vec); }
//------------------------------------------------------------------------------ int main( int argc, char * argv[] ) { //-------------------------------------------------------------------------- const unsigned geomDeg = 1; const unsigned dim = 2; // degrees of lowest-order TH element const unsigned fieldDegU = 2; const unsigned fieldDegP = 1; const unsigned tiOrder = 1; typedef base::time::BDF<tiOrder> MSM; const base::Shape shape = base::SimplexShape<dim>::value; const base::Shape surfShape = base::SimplexShape<dim-1>::value; //-------------------------------------------------------------------------- if ( argc != 2 ) { std::cout << "Usage: " << argv[0] << " input.dat \n\n"; return -1; } const std::string inputFile = boost::lexical_cast<std::string>( argv[1] ); //-------------------------------------------------------------------------- std::string meshFile, surfFile; double viscosity, density, tolerance, penaltyFactor, stepSize; unsigned maxIter, numSteps; { //Feed properties parser with the variables to be read base::io::PropertiesParser prop; prop.registerPropertiesVar( "meshFile", meshFile ); prop.registerPropertiesVar( "surfFile", surfFile ); prop.registerPropertiesVar( "viscosity", viscosity ); prop.registerPropertiesVar( "density", density ); prop.registerPropertiesVar( "maxIter", maxIter ); prop.registerPropertiesVar( "tolerance", tolerance ); prop.registerPropertiesVar( "penaltyFactor", penaltyFactor ); prop.registerPropertiesVar( "stepSize", stepSize ); prop.registerPropertiesVar( "numSteps", numSteps ); // Read variables from the input file std::ifstream inp( inputFile.c_str() ); VERIFY_MSG( inp.is_open(), "Cannot open input file" ); prop.readValues( inp ); inp.close( ); // Make sure all variables have been found if ( not prop.isEverythingRead() ) { prop.writeUnread( std::cerr ); VERIFY_MSG( false, "Could not find above variables" ); } } const std::string baseName = base::io::baseName( meshFile, ".smf" ); //-------------------------------------------------------------------------- typedef base::Unstructured<shape,geomDeg> Mesh; Mesh mesh; { std::ifstream smf( meshFile.c_str() ); VERIFY_MSG( smf.is_open(), "Cannot open mesh file" ); base::io::smf::readMesh( smf, mesh ); smf.close(); } //-------------------------------------------------------------------------- // Surface mesh typedef base::Unstructured<surfShape,1,dim> SurfMesh; SurfMesh surfMesh; { std::ifstream smf( surfFile.c_str() ); base::io::smf::readMesh( smf, surfMesh ); smf.close(); } //-------------------------------------------------------------------------- // Compute the level set data typedef base::cut::LevelSet<dim> LevelSet; std::vector<LevelSet> levelSet; const bool isSigned = true; base::cut::bruteForce( mesh, surfMesh, isSigned, levelSet ); const unsigned kernelDegEstimate = 5; //-------------------------------------------------------------------------- // Make cut cell structure typedef base::cut::Cell<shape> Cell; std::vector<Cell> cells; base::cut::generateCutCells( mesh, levelSet, cells ); // Quadrature typedef base::cut::Quadrature<kernelDegEstimate,shape> CutQuadrature; CutQuadrature quadrature( cells, true ); // for surface typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature; SurfaceQuadrature surfaceQuadrature; //------------------------------------------------------------------------------ // Finite element bases const unsigned nHist = MSM::numSteps; const unsigned doFSizeU = dim; typedef base::fe::Basis<shape,fieldDegU> FEBasisU; typedef base::cut::ScaledField<FEBasisU,doFSizeU,nHist> Velocity; Velocity velocity; base::dof::generate<FEBasisU>( mesh, velocity ); const unsigned doFSizeP = 1; typedef base::fe::Basis<shape,fieldDegP> FEBasisP; typedef base::cut::ScaledField<FEBasisP,doFSizeP,nHist> Pressure; Pressure pressure; base::dof::generate<FEBasisP>( mesh, pressure ); const unsigned doFSizeS = dim; typedef base::fe::Basis<surfShape,1> FEBasisS; typedef base::Field<FEBasisS,doFSizeS> SurfField; SurfField surfVelocity, surfForces; base::dof::generate<FEBasisS>( surfMesh, surfVelocity ); base::dof::generate<FEBasisS>( surfMesh, surfForces ); // set initial condition to the identity base::dof::setField( surfMesh, surfVelocity, boost::bind( &surfaceVelocity<dim, SurfField::DegreeOfFreedom>, _1, _2 ) ); // boundary datum base::cut::TransferSurfaceDatum<SurfMesh,SurfField,Mesh::Element> s2d( surfMesh, surfVelocity, levelSet ); //-------------------------------------------------------------------------- // surface mesh typedef base::mesh::BoundaryMeshBinder<Mesh>::Type BoundaryMesh; BoundaryMesh boundaryMesh, immersedMesh; // from boundary { // identify list of element boundary faces base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); // generate a mesh from that list (with a filter) base::mesh::generateBoundaryMesh( meshBoundary.begin(), meshBoundary.end(), mesh, boundaryMesh, boost::bind( &boundaryFilter<dim>, _1 ) ); // make a surface mesh from the implicit surface base::cut::generateSurfaceMesh<Mesh,Cell>( mesh, cells, immersedMesh ); } // the composite field with geometry, velocity and pressure typedef base::asmb::FieldBinder<Mesh,Velocity,Pressure> Field; Field field( mesh, velocity, pressure ); // define the system blocks (U,U), (U,P), and (P,U) typedef Field::TupleBinder<1,1,1>::Type TopLeft; typedef Field::TupleBinder<1,2>::Type TopRight; typedef Field::TupleBinder<2,1>::Type BotLeft; std::vector<double> supportsU, supportsP; std::size_t numDoFsU = std::distance( velocity.doFsBegin(), velocity.doFsEnd() ); supportsU.resize( numDoFsU ); std::size_t numDoFsP = std::distance( pressure.doFsBegin(), pressure.doFsEnd() ); supportsP.resize( numDoFsP ); base::cut::supportComputation( mesh, velocity, quadrature, supportsU ); base::cut::supportComputation( mesh, pressure, quadrature, supportsP ); velocity.scaleAndTagBasis( supportsU, 1.e-8 ); pressure.scaleAndTagBasis( supportsP, 1.e-8 ); //velocity.tagBasis( supportsU, 1.e-8 ); //pressure.tagBasis( supportsP, 1.e-8 ); // Fix one pressure dof // Pressure::DoFPtrIter pIter = pressure.doFsBegin(); // std::advance( pIter, std::distance( pressure.doFsBegin(), pressure.doFsEnd() )/5 ); // (*pIter) -> constrainValue( 0, 0.0 ); // Number of DoFs after constraint application! numDoFsU = base::dof::numberDoFsConsecutively( velocity.doFsBegin(), velocity.doFsEnd() ); std::cout << "# Number of velocity dofs " << numDoFsU << std::endl; numDoFsP = base::dof::numberDoFsConsecutively( pressure.doFsBegin(), pressure.doFsEnd(), numDoFsU ); std::cout << "# Number of pressure dofs " << numDoFsP << std::endl; // kernels typedef fluid::StressDivergence< TopLeft::Tuple> StressDivergence; typedef fluid::Convection< TopLeft::Tuple> Convection; typedef fluid::PressureGradient< TopRight::Tuple> GradP; typedef fluid::VelocityDivergence<BotLeft::Tuple> DivU; StressDivergence stressDivergence( viscosity ); Convection convection( density ); GradP gradP; DivU divU( true ); // for surface fields typedef base::asmb::SurfaceFieldBinder<BoundaryMesh,Velocity,Pressure> SurfaceFieldBinder; typedef SurfaceFieldBinder::TupleBinder<1,1,1>::Type STBUU; typedef SurfaceFieldBinder::TupleBinder<1,2 >::Type STBUP; SurfaceFieldBinder boundaryFieldBinder( boundaryMesh, velocity, pressure ); SurfaceFieldBinder immersedFieldBinder( immersedMesh, velocity, pressure ); std::ofstream forces( "forces.dat" ); for ( unsigned step = 0; step < numSteps; step++ ) { const double time = step * stepSize; const double factor = ( time < 1.0 ? time : 1.0 ); std::cout << step << ": time=" << time << ", factor=" << factor << "\n"; //base::dof::clearDoFs( velocity ); //base::dof::clearDoFs( pressure ); //-------------------------------------------------------------------------- // Nonlinear iterations unsigned iter = 0; while( iter < maxIter ) { // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( numDoFsU + numDoFsP ); std::cout << "* Iteration " << iter << std::flush; // compute inertia terms, d/dt, due to time integration base::time::computeInertiaTerms<TopLeft,MSM>( quadrature, solver, field, stepSize, step, density ); // Compute system matrix base::asmb::stiffnessMatrixComputation<TopLeft>( quadrature, solver, field, stressDivergence ); base::asmb::stiffnessMatrixComputation<TopLeft>( quadrature, solver, field, convection ); base::asmb::stiffnessMatrixComputation<TopRight>( quadrature, solver, field, gradP ); base::asmb::stiffnessMatrixComputation<BotLeft>( quadrature, solver, field, divU ); // compute residual forces base::asmb::computeResidualForces<TopLeft >( quadrature, solver, field, stressDivergence ); base::asmb::computeResidualForces<TopLeft >( quadrature, solver, field, convection ); base::asmb::computeResidualForces<TopRight>( quadrature, solver, field, gradP ); base::asmb::computeResidualForces<BotLeft >( quadrature, solver, field, divU ); // Parameter classes base::nitsche::OuterBoundary ob( viscosity ); base::nitsche::ImmersedBoundary<Cell> ib( viscosity, cells ); // Penalty method base::nitsche::penaltyLHS<STBUU>( surfaceQuadrature, solver, boundaryFieldBinder, ob, penaltyFactor ); base::nitsche::penaltyRHS<STBUU>( surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1, factor), ob, penaltyFactor ); base::nitsche::penaltyLHS<STBUU>( surfaceQuadrature, solver, immersedFieldBinder, ib, penaltyFactor ); base::nitsche::penaltyRHS2<STBUU>( surfaceQuadrature, solver, immersedFieldBinder, s2d, ib, penaltyFactor ); // Nitsche terms base::nitsche::primalEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver, boundaryFieldBinder, ob ); base::nitsche::dualEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver, boundaryFieldBinder, ob ); base::nitsche::energyRHS<STBUU>( stressDivergence, surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1, factor), ob ); base::nitsche::primalEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver, boundaryFieldBinder, ob ); base::nitsche::dualEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver, boundaryFieldBinder, ob ); base::nitsche::energyRHS<STBUP>( gradP, surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1, factor), ob ); base::nitsche::energyResidual<STBUU>( stressDivergence, surfaceQuadrature, solver, boundaryFieldBinder, ob ); base::nitsche::energyResidual<STBUP>( gradP, surfaceQuadrature, solver, boundaryFieldBinder, ob ); base::nitsche::primalEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver, immersedFieldBinder, ib ); base::nitsche::dualEnergyLHS<STBUU>( stressDivergence, surfaceQuadrature, solver, immersedFieldBinder, ib ); base::nitsche::energyRHS2<STBUU>( stressDivergence, surfaceQuadrature, solver, immersedFieldBinder, s2d, ib ); base::nitsche::primalEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver, immersedFieldBinder, ib ); base::nitsche::dualEnergyLHS<STBUP>( gradP, surfaceQuadrature, solver, immersedFieldBinder, ib ); base::nitsche::energyRHS2<STBUP>( gradP, surfaceQuadrature, solver, immersedFieldBinder, s2d, ib ); base::nitsche::energyResidual<STBUU>( stressDivergence, surfaceQuadrature, solver, immersedFieldBinder, ib ); base::nitsche::energyResidual<STBUP>( gradP, surfaceQuadrature, solver, immersedFieldBinder, ib ); // Finalise assembly solver.finishAssembly(); // check convergence via solver norms const double residualNorm = solver.norm(); std::cout << " |R| = " << residualNorm << std::flush; if ( residualNorm < tolerance * viscosity) { std::cout << std::endl; break; } // Solve solver.superLUSolve(); // distribute results back to dofs base::dof::addToDoFsFromSolver( solver, velocity ); base::dof::addToDoFsFromSolver( solver, pressure ); //base::dof::setDoFsFromSolver( solver, pressure ); // check convergence via solver norms const double incrementNorm = solver.norm(0, numDoFsU ); std::cout << " |dU| = " << incrementNorm << std::endl; // push history base::dof::pushHistory( velocity ); base::dof::pushHistory( pressure ); if ( incrementNorm < tolerance ) break; iter++; } writeVTKFile( baseName, step, mesh, velocity, pressure, levelSet, viscosity ); { base::Vector<dim>::Type sumOfForces = base::constantVector<dim>( 0. ); typedef Field::TupleBinder<1,2>::Type UP; //typedef fluid::Stress<UP::Tuple> Stress; //Stress stress( viscosity ); typedef fluid::Traction<UP::Tuple> Traction; Traction traction( viscosity ); base::cut::ComputeSurfaceForces<SurfMesh,SurfField, SurfaceQuadrature,STBUP::Tuple,Traction> computeSurfaceForces( surfMesh, surfForces, surfaceQuadrature, levelSet, traction ); SurfaceFieldBinder::FieldIterator first = immersedFieldBinder.elementsBegin(); SurfaceFieldBinder::FieldIterator last = immersedFieldBinder.elementsEnd(); for ( ; first != last; ++first ) { sumOfForces += computeSurfaceForces( STBUP::makeTuple( *first ) ); } writeSurfaceVTKFile( baseName, step, surfMesh, surfVelocity, surfForces ); std::cout << " F= " << sumOfForces.transpose() << " \n"; forces << time << " " << sumOfForces.transpose() << std::endl;; } } forces.close(); return 0; }
void ElasticMembranePressure<PressureType>::element_time_derivative ( bool compute_jacobian, AssemblyContext & context ) { unsigned int u_var = this->_disp_vars.u(); unsigned int v_var = this->_disp_vars.v(); unsigned int w_var = this->_disp_vars.w(); const unsigned int n_u_dofs = context.get_dof_indices(u_var).size(); const std::vector<libMesh::Real> &JxW = this->get_fe(context)->get_JxW(); const std::vector<std::vector<libMesh::Real> >& u_phi = this->get_fe(context)->get_phi(); const MultiphysicsSystem & system = context.get_multiphysics_system(); unsigned int u_dot_var = system.get_second_order_dot_var(u_var); unsigned int v_dot_var = system.get_second_order_dot_var(v_var); unsigned int w_dot_var = system.get_second_order_dot_var(w_var); libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(u_dot_var); libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(v_dot_var); libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(w_dot_var); libMesh::DenseSubMatrix<libMesh::Number>& Kuv = context.get_elem_jacobian(u_dot_var,v_var); libMesh::DenseSubMatrix<libMesh::Number>& Kuw = context.get_elem_jacobian(u_dot_var,w_var); libMesh::DenseSubMatrix<libMesh::Number>& Kvu = context.get_elem_jacobian(v_dot_var,u_var); libMesh::DenseSubMatrix<libMesh::Number>& Kvw = context.get_elem_jacobian(v_dot_var,w_var); libMesh::DenseSubMatrix<libMesh::Number>& Kwu = context.get_elem_jacobian(w_dot_var,u_var); libMesh::DenseSubMatrix<libMesh::Number>& Kwv = context.get_elem_jacobian(w_dot_var,v_var); unsigned int n_qpoints = context.get_element_qrule().n_points(); // All shape function gradients are w.r.t. master element coordinates const std::vector<std::vector<libMesh::Real> >& dphi_dxi = this->get_fe(context)->get_dphidxi(); const std::vector<std::vector<libMesh::Real> >& dphi_deta = this->get_fe(context)->get_dphideta(); const libMesh::DenseSubVector<libMesh::Number>& u_coeffs = context.get_elem_solution( u_var ); const libMesh::DenseSubVector<libMesh::Number>& v_coeffs = context.get_elem_solution( v_var ); const libMesh::DenseSubVector<libMesh::Number>& w_coeffs = context.get_elem_solution( w_var ); const std::vector<libMesh::RealGradient>& dxdxi = this->get_fe(context)->get_dxyzdxi(); const std::vector<libMesh::RealGradient>& dxdeta = this->get_fe(context)->get_dxyzdeta(); for (unsigned int qp=0; qp != n_qpoints; qp++) { // sqrt(det(a_cov)), a_cov being the covariant metric tensor of undeformed body libMesh::Real sqrt_a = sqrt( dxdxi[qp]*dxdxi[qp]*dxdeta[qp]*dxdeta[qp] - dxdxi[qp]*dxdeta[qp]*dxdeta[qp]*dxdxi[qp] ); // Gradients are w.r.t. master element coordinates libMesh::Gradient grad_u, grad_v, grad_w; for( unsigned int d = 0; d < n_u_dofs; d++ ) { libMesh::RealGradient u_gradphi( dphi_dxi[d][qp], dphi_deta[d][qp] ); grad_u += u_coeffs(d)*u_gradphi; grad_v += v_coeffs(d)*u_gradphi; grad_w += w_coeffs(d)*u_gradphi; } libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) ); libMesh::RealGradient dudeta( grad_u(1), grad_v(1), grad_w(1) ); libMesh::RealGradient A_1 = dxdxi[qp] + dudxi; libMesh::RealGradient A_2 = dxdeta[qp] + dudeta; libMesh::RealGradient A_3 = A_1.cross(A_2); // Compute pressure at this quadrature point libMesh::Real press = (*_pressure)(context,qp); // Small optimization libMesh::Real p_over_sa = press/sqrt_a; /* The formula here is actually P*\sqrt{\frac{A}{a}}*A_3, where A_3 is a unit vector But, |A_3| = \sqrt{A} so the normalizing part kills the \sqrt{A} in the numerator, so we can leave it out and *not* normalize A_3. */ libMesh::RealGradient traction = p_over_sa*A_3; for (unsigned int i=0; i != n_u_dofs; i++) { // Small optimization libMesh::Real phi_times_jac = u_phi[i][qp]*JxW[qp]; Fu(i) -= traction(0)*phi_times_jac; Fv(i) -= traction(1)*phi_times_jac; Fw(i) -= traction(2)*phi_times_jac; if( compute_jacobian ) { for (unsigned int j=0; j != n_u_dofs; j++) { libMesh::RealGradient u_gradphi( dphi_dxi[j][qp], dphi_deta[j][qp] ); const libMesh::Real dt0_dv = p_over_sa*(u_gradphi(0)*A_2(2) - A_1(2)*u_gradphi(1)); const libMesh::Real dt0_dw = p_over_sa*(A_1(1)*u_gradphi(1) - u_gradphi(0)*A_2(1)); const libMesh::Real dt1_du = p_over_sa*(A_1(2)*u_gradphi(1) - u_gradphi(0)*A_2(2)); const libMesh::Real dt1_dw = p_over_sa*(u_gradphi(0)*A_2(0) - A_1(0)*u_gradphi(1)); const libMesh::Real dt2_du = p_over_sa*(u_gradphi(0)*A_2(1) - A_1(1)*u_gradphi(1)); const libMesh::Real dt2_dv = p_over_sa*(A_1(0)*u_gradphi(1) - u_gradphi(0)*A_2(0)); Kuv(i,j) -= dt0_dv*phi_times_jac; Kuw(i,j) -= dt0_dw*phi_times_jac; Kvu(i,j) -= dt1_du*phi_times_jac; Kvw(i,j) -= dt1_dw*phi_times_jac; Kwu(i,j) -= dt2_du*phi_times_jac; Kwv(i,j) -= dt2_dv*phi_times_jac; } } } } }
/* == Incompressible deformation: 2D shape hanging under gravity with a balancing traction == * * We now repeat the above test but include a traction on the bottom surface (Y=0). We apply this * in the inward direction so that is counters (somewhat) the effect of gravity. We also show how stresses * and strains can be written to file. */ void TestIncompressibleProblemWithTractions() throw(Exception) { /* All of this is exactly as above */ QuadraticMesh<2> mesh; mesh.ConstructRegularSlabMesh(0.1 /*stepsize*/, 0.8 /*width*/, 1.0 /*height*/); MooneyRivlinMaterialLaw<2> law(1.0); c_vector<double,2> body_force; body_force(0) = 0.0; body_force(1) = -2.0; std::vector<unsigned> fixed_nodes = NonlinearElasticityTools<2>::GetNodesByComponentValue(mesh, 1, 1.0); /* Now the traction boundary conditions. We need to collect all the boundary elements on the surface which we want to * apply non-zero tractions, put them in a `std::vector`, and create a corresponding `std::vector` of the tractions * for each of the boundary elements. Note that the each traction is a 2D vector with dimensions of pressure. * * First, declare the data structures: */ std::vector<BoundaryElement<1,2>*> boundary_elems; std::vector<c_vector<double,2> > tractions; /* Create a constant traction */ c_vector<double,2> traction; traction(0) = 0; traction(1) = 1.0; // this choice of sign corresponds to an inward force (if applied to the bottom surface) /* Loop over boundary elements */ for (TetrahedralMesh<2,2>::BoundaryElementIterator iter = mesh.GetBoundaryElementIteratorBegin(); iter != mesh.GetBoundaryElementIteratorEnd(); ++iter) { /* If the centre of the element has Y value of 0.0, it is on the surface we need */ if (fabs((*iter)->CalculateCentroid()[1] - 0.0) < 1e-6) { /* Put the boundary element and the constant traction into the stores. */ BoundaryElement<1,2>* p_element = *iter; boundary_elems.push_back(p_element); tractions.push_back(traction); } } /* A quick check */ assert(boundary_elems.size() == 8u); /* Now create the problem definition object, setting the material law, fixed nodes and body force as * before (this time not calling `SetDensity()`, so using the default density of 1.0, * and also calling a method for setting tractions, which takes in the boundary elements * and tractions for each of those elements. */ SolidMechanicsProblemDefinition<2> problem_defn(mesh); problem_defn.SetMaterialLaw(INCOMPRESSIBLE,&law); problem_defn.SetZeroDisplacementNodes(fixed_nodes); problem_defn.SetBodyForce(body_force); problem_defn.SetTractionBoundaryConditions(boundary_elems, tractions); /* Create solver as before */ IncompressibleNonlinearElasticitySolver<2> solver(mesh, problem_defn, "IncompressibleElasticityWithTractionsTutorial"); /* In this test we also output the stress and strain. For the former, we have to tell the solver to store * the stresses that are computed during the solve. */ solver.SetComputeAverageStressPerElementDuringSolve(); /* Call `Solve()` */ solver.Solve(); /* If VTK output is written (discussed above) strains can be visualised. Alternatively, we can create text files * for strains and stresses by doing the following. * * Write the final deformation gradients to file. The i-th line of this file provides the deformation gradient F, * written as 'F(0,0) F(0,1) F(1,0) F(1,1)', evaluated at the centroid of the i-th element. The first variable * can also be DEFORMATION_TENSOR_C or LAGRANGE_STRAIN_E to write C or E. The second parameter is the file name. */ solver.WriteCurrentStrains(DEFORMATION_GRADIENT_F,"deformation_grad"); /* Since we called `SetComputeAverageStressPerElementDuringSolve`, we can write the stresses to file too. However, * note that for each element this is not the stress evaluated at the centroid, but the mean average of the stresses * evaluated at the quadrature points - for technical cardiac electromechanics reasons, it is difficult to * define the stress at non-quadrature points. */ solver.WriteCurrentAverageElementStresses("2nd_PK_stress"); /* Another quick check */ TS_ASSERT_EQUALS(solver.GetNumNewtonIterations(), 4u); /* Visualise as before by going to the output directory and doing * `x=load('solution.nodes'); plot(x(:,1),x(:,2),'m*')` in Matlab/octave, or by using Cmgui. * The effect of the traction should be clear (especially when compared to * the results of the first test). * * Create Cmgui output */ solver.CreateCmguiOutput(); /* This is just to check that nothing has been accidentally changed in this test */ TS_ASSERT_DELTA(solver.rGetDeformedPosition()[8](0), 0.8561, 1e-3); TS_ASSERT_DELTA(solver.rGetDeformedPosition()[8](1), 0.0310, 1e-3); }
static c_vector<double,3> GetTraction(c_vector<double,3>& rX, double t) { c_vector<double,3> traction = zero_vector<double>(3); double lam1 = 1+a*rX(0); double lam2 = 1+b*rX(1); double invlam1 = 1.0/lam1; double invlam2 = 1.0/lam2; double Z = rX(2); if ( fabs(rX(0)-1)<1e-6 ) { traction(0) = lam1 - invlam1; traction(1) = 0.0; traction(2) = -a*Z*invlam1*invlam1*invlam2; } else if ( fabs(rX(1)-0)<1e-6 ) { traction(0) = 0.0; traction(1) = 0.0; traction(2) = b*Z*invlam1; } else if ( fabs(rX(1)-1)<1e-6 ) { traction(0) = 0.0; traction(1) = lam2 - invlam2; traction(2) = -b*Z*invlam2*invlam2*invlam1; } else if ( fabs(rX(2)-0)<1e-6 ) { traction(0) = 0.0; traction(1) = 0.0; traction(2) = lam1*lam2 - invlam1*invlam2; } else if ( fabs(rX(2)-1)<1e-6 ) { traction(0) = -a*invlam1*invlam1; traction(1) = -b*invlam2*invlam2; traction(2) = invlam1*invlam2 - lam1*lam2; } else { NEVER_REACHED; } return 2*c1*traction; }
void main(){ int gdriver = EGA, gmode = EGAHI, errorcode; initgraph(&gdriver, &gmode, "c:\\tc\\bgi"); bk(); travel(); gravitas(); tvar=0; m1c=m2c=adc=chdc=0; signup_traction(); while(ch!=27) { if(kbhit()) { ch=getch(); if(ch==77) {way(1);} if(ch==75) {way(0);} if(ch==80) {menu1();setcolor(6);settextstyle(2,0,4); outtextxy(68,180,"<-");break;} }} flag1: city(); m1c=0; while(ch!=27) { gravitas(); if(kbhit()) { ch=getch(); if(ch==80 && m1c<=15) //i city {menu1();city();++m1c;ibar();tarrow(m1c);mcounter(m1c);} if(ch==72 && m1c>=1 && m1c<=15) {menu1();city();m1c--;ibar();tarrow(m1c);mcounter(m1c);} if(ch==80 && m1c>=16 && m1c<=33) //2 city {menu1();city2();m1c++;ibar();tarrow(m1c);mcounter(m1c);} if(ch==72 && m1c>=16 && m1c<=33) {menu1();city2();m1c--;ibar();tarrow(m1c);mcounter(m1c);} if(ch==80 && m1c>=34 && m1c<=51) //3 city {menu1();city3();m1c++;ibar();tarrow(m1c);mcounter(m1c);} if(ch==72 && m1c>=34 && m1c<=51) {menu1();city3();m1c--;ibar();tarrow(m1c);mcounter(m1c);} if(ch==80 && m1c>=52 && m1c<56) //4 city {menu1();city4();m1c++;ibar();tarrow(m1c);mcounter(m1c);} if(ch==72 && m1c>=52 && m1c<=56) {menu1();city4();m1c--;ibar();tarrow(m1c);mcounter(m1c);} if(ch==13) {from=m1c; bk(); travel(); mcounter(m1c);from=m1c;if(tvar)tmcounter(m2c);break;} if(ch==77) { bk();travel();menu2();tcity();mcounter(m1c);from=m1c;menu2();break;} }} //flag2: m2c=0; while(ch!=27) { gravitas(); if(kbhit()) { ch=getch(); if(ch==80 && m2c<=15) //i city {menu2();tcity();++m2c;tbar();arrow(m2c);tmcounter(m2c);} if(ch==72 && m2c>=1 && m2c<=15) {menu2();tcity();m2c--;tbar();arrow(m2c);tmcounter(m2c);} if(ch==80 && m2c>=16 && m2c<=33) //2 city {menu2();tcity2();m2c++;tbar();arrow(m2c);tmcounter(m2c);} if(ch==72 && m2c>=16 && m2c<=33) {menu2();tcity2();m2c--;tbar();arrow(m2c);tmcounter(m2c);} if(ch==80 && m2c>=34 && m2c<=51) //3 city {menu2();tcity3();m2c++;tbar();arrow(m2c);tmcounter(m2c);} if(ch==72 && m2c>=34 && m2c<=51) {menu2();tcity3();m2c--;tbar();arrow(m2c);tmcounter(m2c);} if(ch==80 && m2c>=52 && m2c<56) //4 city {menu2();tcity4();m2c++;tbar();arrow(m2c);tmcounter(m2c);} if(ch==72 && m2c>=52 && m2c<=56) {menu2();tcity4();m2c--;tbar();arrow(m2c);tmcounter(m2c);} if(ch==13) {to=m2c; bk(); travel(); tvar=1;tmcounter(m2c);to=m2c;mcounter(m1c);break;} if(ch==75) {bk();travel(); to =m2c; tvar=1; tmcounter(m2c);to=m2c;menu1(); //goto flag1; break;} } } while(ch!=27) { gravitas(); if(kbhit()) { ch=getch(); if(ch==80 && adc<10) {admenu();adult(); adc++; adarrow(adc); adcounter(adc);} if(ch==72 && adc>0) {admenu();adult(); adc--; adarrow(adc);adcounter(adc);} if(ch==77) {adno=adc;chmenu();bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);break;} if(ch==13) {adno=adc;bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);break;} }} while(ch!=27) { gravitas(); if(kbhit()) { ch=getch(); if(ch==80 && chdc<10) {chmenu();child(); chdc++; charrow(chdc); chcounter(chdc);} if(ch==72 && chdc>0) {chmenu();child(); chdc--; charrow(chdc);chcounter(chdc);} if(ch==77) {chno=chdc;chmenu();bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc); break;} if(ch==13) {chno=chdc;bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc); break;} }} while(ch!=27) { gravitas(); if(kbhit()) { ch=getch(); if(ch==80 && inc<10) {inmenu();infant(); inc++; inarrow(inc); incounter(inc);} if(ch==72 && inc>0) {inmenu();infant(); inc--; inarrow(inc);incounter(inc);} if(ch==77) {inno=inc;inmenu();bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc);incounter(inc); break;} if(ch==13) {inno=chdc;bk(); travel();tmcounter(m2c);mcounter(m1c);adcounter(adc);chcounter(chdc);incounter(inc); break;} }} while(ch!=27) { gravitas(); if(kbhit()) { ch=getch(); if(ch==77) {ecob(1);suit=1;} if(ch==75) {ecob(0);suit=0;} if(ch==13) {break;} } } setcolor(1);settextstyle(2,0,4); ch=0; while(ch!=13) { if(kbhit()) {da+=8; ch=getch(); if(isalnum(ch) && da<=95) {sprintf(dater,"%c",ch); outtextxy(da,272,dater);} if(ch==8 && da>=45 && da<=180) {da=da-8; setfillstyle(1,15); bar(da,272,da+8,285); da=da-8;} }} if(suit==0)flight(to); if(suit==1)bflight(to); traction(); secure(); money_transfer(); getch(); closegraph();}
void ElasticMembraneConstantPressure::element_time_derivative( bool compute_jacobian, AssemblyContext& context, CachedValues& /*cache*/ ) { const unsigned int n_u_dofs = context.get_dof_indices(_disp_vars.u()).size(); const std::vector<libMesh::Real> &JxW = this->get_fe(context)->get_JxW(); const std::vector<std::vector<libMesh::Real> >& u_phi = this->get_fe(context)->get_phi(); libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_disp_vars.u()); libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_disp_vars.v()); libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(_disp_vars.w()); libMesh::DenseSubMatrix<libMesh::Number>& Kuv = context.get_elem_jacobian(_disp_vars.u(),_disp_vars.v()); libMesh::DenseSubMatrix<libMesh::Number>& Kuw = context.get_elem_jacobian(_disp_vars.u(),_disp_vars.w()); libMesh::DenseSubMatrix<libMesh::Number>& Kvu = context.get_elem_jacobian(_disp_vars.v(),_disp_vars.u()); libMesh::DenseSubMatrix<libMesh::Number>& Kvw = context.get_elem_jacobian(_disp_vars.v(),_disp_vars.w()); libMesh::DenseSubMatrix<libMesh::Number>& Kwu = context.get_elem_jacobian(_disp_vars.w(),_disp_vars.u()); libMesh::DenseSubMatrix<libMesh::Number>& Kwv = context.get_elem_jacobian(_disp_vars.w(),_disp_vars.v()); unsigned int n_qpoints = context.get_element_qrule().n_points(); // All shape function gradients are w.r.t. master element coordinates const std::vector<std::vector<libMesh::Real> >& dphi_dxi = this->get_fe(context)->get_dphidxi(); const std::vector<std::vector<libMesh::Real> >& dphi_deta = this->get_fe(context)->get_dphideta(); const libMesh::DenseSubVector<libMesh::Number>& u_coeffs = context.get_elem_solution( _disp_vars.u() ); const libMesh::DenseSubVector<libMesh::Number>& v_coeffs = context.get_elem_solution( _disp_vars.v() ); const libMesh::DenseSubVector<libMesh::Number>& w_coeffs = context.get_elem_solution( _disp_vars.w() ); const std::vector<libMesh::RealGradient>& dxdxi = this->get_fe(context)->get_dxyzdxi(); const std::vector<libMesh::RealGradient>& dxdeta = this->get_fe(context)->get_dxyzdeta(); for (unsigned int qp=0; qp != n_qpoints; qp++) { // sqrt(det(a_cov)), a_cov being the covariant metric tensor of undeformed body libMesh::Real sqrt_a = sqrt( dxdxi[qp]*dxdxi[qp]*dxdeta[qp]*dxdeta[qp] - dxdxi[qp]*dxdeta[qp]*dxdeta[qp]*dxdxi[qp] ); // Gradients are w.r.t. master element coordinates libMesh::Gradient grad_u, grad_v, grad_w; for( unsigned int d = 0; d < n_u_dofs; d++ ) { libMesh::RealGradient u_gradphi( dphi_dxi[d][qp], dphi_deta[d][qp] ); grad_u += u_coeffs(d)*u_gradphi; grad_v += v_coeffs(d)*u_gradphi; grad_w += w_coeffs(d)*u_gradphi; } libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) ); libMesh::RealGradient dudeta( grad_u(1), grad_v(1), grad_w(1) ); libMesh::RealGradient A_1 = dxdxi[qp] + dudxi; libMesh::RealGradient A_2 = dxdeta[qp] + dudeta; libMesh::RealGradient A_3 = A_1.cross(A_2); /* The formula here is actually P*\sqrt{\frac{A}{a}}*A_3, where A_3 is a unit vector But, |A_3| = \sqrt{A} so the normalizing part kills the \sqrt{A} in the numerator, so we can leave it out and *not* normalize A_3. */ libMesh::RealGradient traction = _pressure/sqrt_a*A_3; libMesh::Real jac = JxW[qp]; for (unsigned int i=0; i != n_u_dofs; i++) { Fu(i) -= traction(0)*u_phi[i][qp]*jac; Fv(i) -= traction(1)*u_phi[i][qp]*jac; Fw(i) -= traction(2)*u_phi[i][qp]*jac; if( compute_jacobian ) { for (unsigned int j=0; j != n_u_dofs; j++) { libMesh::RealGradient u_gradphi( dphi_dxi[j][qp], dphi_deta[j][qp] ); const libMesh::Real dt0_dv = _pressure/sqrt_a*(u_gradphi(0)*A_2(2) - A_1(2)*u_gradphi(1)); const libMesh::Real dt0_dw = _pressure/sqrt_a*(A_1(1)*u_gradphi(1) - u_gradphi(0)*A_2(1)); const libMesh::Real dt1_du = _pressure/sqrt_a*(A_1(2)*u_gradphi(1) - u_gradphi(0)*A_2(2)); const libMesh::Real dt1_dw = _pressure/sqrt_a*(u_gradphi(0)*A_2(0) - A_1(0)*u_gradphi(1)); const libMesh::Real dt2_du = _pressure/sqrt_a*(u_gradphi(0)*A_2(1) - A_1(1)*u_gradphi(1)); const libMesh::Real dt2_dv = _pressure/sqrt_a*(A_1(0)*u_gradphi(1) - u_gradphi(0)*A_2(0)); Kuv(i,j) -= dt0_dv*u_phi[i][qp]*jac; Kuw(i,j) -= dt0_dw*u_phi[i][qp]*jac; Kvu(i,j) -= dt1_du*u_phi[i][qp]*jac; Kvw(i,j) -= dt1_dw*u_phi[i][qp]*jac; Kwu(i,j) -= dt2_du*u_phi[i][qp]*jac; Kwv(i,j) -= dt2_dv*u_phi[i][qp]*jac; } } } } return; }