MMappedReader(const std::string &filename, bool unlink = false, size_t blocksize = 64*1024*1024, size_t off = 0, size_t sz = 0) : Unlink(unlink), FileName(filename), BlockSize(blocksize) { struct stat buf; FileSize = (sz ? sz : (stat(FileName.c_str(), &buf) != 0 ? 0 : buf.st_size)); StreamFile = open(FileName.c_str(), O_RDONLY); VERIFY_MSG(StreamFile != -1, "open(2) failed. Reason: " << strerror(errno) << ". Error code: " << errno); if (BlockSize != -1ULL) { size_t PageSize = getpagesize(); BlockSize = BlockSize / PageSize * PageSize; } else BlockSize = FileSize; if (BlockSize) { MappedRegion = (uint8_t*)mmap(NULL, BlockSize, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, StreamFile, off); VERIFY_MSG((intptr_t)MappedRegion != -1L, "mmap(2) failed. Reason: " << strerror(errno) << ". Error code: " << errno); } else MappedRegion = NULL; BlockOffset = BytesRead = 0; }
void base::mesh::createBoundaryFromStructuredFace( const typename base::MultiIndex<DIM>::Type& gridSizes, const unsigned direction, const unsigned side, std::vector< std::pair<std::size_t,unsigned> >& boundaryElementContainer ) { VERIFY_MSG( (direction < DIM), "Direction is nonsense "); VERIFY_MSG( (side==0) or (side==1), "Side ID is nonsense" ); // fixed number const int fixed = ( side == 0 ? 0 : gridSizes[ direction ] - 1 ); // number of element faces typedef typename base::MultiIndex<DIM-1> FaceMI; typedef typename FaceMI::Type FaceMIT; FaceMIT numFacesM; unsigned ctr = 0; for ( unsigned d = 0; d < DIM; d++ ) if ( d != direction ) numFacesM[ctr++] = gridSizes[d]; const unsigned numFaces = static_cast<unsigned>( FaceMI::length( numFacesM ) ); // face number const unsigned faceNum = detail_::FaceNumberLookUp<DIM>::apply( direction, side ); // go through all faces for ( unsigned f = 0; f < numFaces; f ++ ) { // multi-index on the grid face const FaceMIT fM = FaceMI::wrap( f, numFacesM ); // construct domain face index typename base::MultiIndex<DIM>::Type domIndexM; unsigned ctr = 0; for ( unsigned d = 0; d < DIM; d++ ) { if ( d == direction ) domIndexM[d] = fixed; else domIndexM[d] = fM[ctr++]; } // linearise const std::size_t domIndex = base::MultiIndex<DIM>::unwrap( domIndexM, gridSizes ); // store pair of element number and face number boundaryElementContainer.push_back( std::make_pair( domIndex, faceNum ) ); } return; }
inline size_t get_memory_limit() { rlimit rl; int res = getrlimit(RLIMIT_AS, &rl); VERIFY_MSG(res == 0, "getrlimit(2) call failed, errno = " << errno); return rl.rlim_cur; }
inline rlim_t limit_file(size_t limit) { struct rlimit rl; int res = getrlimit(RLIMIT_NOFILE, &rl); VERIFY_MSG(res == 0, "getrlimit(2) call failed, errno = " << errno); // We cannot go beyond hard limit and we might not have enough privileges to // increase the hard limit limit = std::max<size_t>(limit, rl.rlim_cur); rl.rlim_cur = std::min<size_t>(limit, rl.rlim_max); res = setrlimit(RLIMIT_NOFILE, &rl); VERIFY_MSG(res == 0, "setrlimit(2) call failed, errno = " << errno); INFO("Open file limit set to " << rl.rlim_cur); return rl.rlim_cur; }
inline void limit_memory(size_t limit) { rlimit rl; if (sizeof(rlim_t) < 8) { INFO("Can't limit virtual memory because of 32-bit system"); return; } int res = getrlimit(RLIMIT_AS, &rl); VERIFY_MSG(res == 0, "getrlimit(2) call failed, errno = " << errno); // We cannot go beyond hard limit and we might not have enough privileges to // increase the hard limit rl.rlim_cur = std::min<size_t>(limit, rl.rlim_max); res = setrlimit(RLIMIT_AS, &rl); VERIFY_MSG(res == 0, "setrlimit(2) call failed, errno = " << errno); INFO("Memory limit set to " << (1.0 * (double)rl.rlim_cur / 1024 / 1024 / 1024) << " Gb"); }
/** Function call operator doing the main job * \param[out] mesh The mesh constructed from the file input * \param[in] smf Input stream with the SMF-specified geometry */ void operator()( Mesh & mesh, std::istream & smf ) const { // Read header and validate it std::pair<bool,std::string> externalNodes = std::make_pair( false, ""); std::pair<bool,std::string> externalElements = std::make_pair( false, ""); const bool validHeader = this -> readAndValidateHeader_( smf, externalNodes, externalElements ); VERIFY_MSG( validHeader, "Smf header is invalid" ); unsigned nNodes, nElements; this -> readNumbers_( smf, nNodes, nElements ); mesh.allocate( nNodes, nElements ); // Read coordinates and pass them to the nodes if ( externalNodes.first ) { std::ifstream smfNodesExt( externalNodes.second.c_str() ); if ( not smfNodesExt.is_open() ) { std::cerr << "Failed to open " << externalNodes.second << '\n'; VERIFY_MSG( false, "IO Error (see above) " ); } this -> readAndSetNodes_( smfNodesExt, mesh ); smfNodesExt.close(); } else this -> readAndSetNodes_( smf, mesh ); // Read elements' connectivities and pass them to the elements if ( externalElements.first ) { std::ifstream smfConnExt( externalElements.second.c_str() ); if ( not smfConnExt.is_open() ) { std::cerr << "Failed to open " << externalElements.second << '\n'; VERIFY_MSG( false, "IO Error (see above) " ); } this -> readAndSetElements_( smfConnExt, mesh ); smfConnExt.close(); } else this -> readAndSetElements_( smf, mesh ); }
virtual ~MMappedReader() { if (StreamFile != -1) close(StreamFile); if (MappedRegion) munmap(MappedRegion, BlockSize); if (Unlink) { int res = unlink(FileName.c_str()); VERIFY_MSG(res == 0, "unlink(2) failed. Reason: " << strerror(errno) << ". Error code: " << errno); } }
void generateMesh( MESH& mesh, const UIN& userInput ) { if ( userInput.readMeshFromFile ) { std::ifstream smf( userInput.meshFile.c_str() ); VERIFY_MSG( smf.is_open(), x2s("Cannot find input file ") + userInput.meshFile ); base::io::smf::readMesh( smf, mesh ); } else { ::generateMesh<UIN::dim>( mesh, userInput.N, userInput.bbmin, userInput.bbmax ); } }
void constrainSupports( FIELD& field ) { VERIFY_MSG( (FIELD::DegreeOfFreedom::size==2), "This method only works for 2D" ); typename FIELD::DoFPtrIter dIter = field.doFsBegin(); const std::size_t numDoFs = std::distance( dIter, field.doFsEnd() ); VERIFY_MSG( (numDoFs % 4) == 0, "Trying to fix the quarter points" ); (*dIter) -> constrainValue( 1, 0. ); std::advance( dIter, numDoFs/4 ); (*dIter) -> constrainValue( 0, 0. ); std::advance( dIter, numDoFs/4 ); (*dIter) -> constrainValue( 1, 0. ); std::advance( dIter, numDoFs/4 ); (*dIter) -> constrainValue( 0, 0. ); }
bool DicomRasterPager::openFile(const std::string &filename) { mpImage.reset(new DicomImage(filename.c_str())); if(mpImage->getStatus() != EIS_Normal) { VERIFY_MSG(false, DicomImage::getString(mpImage->getStatus())); } if((mpImage->getPhotometricInterpretation() == EPI_RGB || mpImage->getPhotometricInterpretation() == EPI_PaletteColor) && static_cast<const RasterDataDescriptor*>(getRasterElement()->getDataDescriptor())->getBandCount() != mpImage->getFrameCount()) { mConvertRgb = true; } return true; }
/** Write itself and write either CData or child tags * \param[in] out Stream for output * \param[in] indentLevel Level of indentation for legibility */ void write( std::ostream & out, const unsigned indentLevel = 0 ) const { std::string indent( 2 * indentLevel, ' ' ); out << indent << "<" << name_ << " "; // write attributes; for ( unsigned a = 0; a < attributes_.size(); a ++ ) { out << attributes_[a].first << "=\"" << attributes_[a].second << "\""; if ( a < (attributes_.size() - 1) ) out << " "; } // check children const bool noChildren = children_.empty(); // check cdata_ const bool noCData = (cData_ == NULL); // closing symbol if ( noChildren and noCData ) { out << "/> \n"; } else out << "> \n"; // sanity check VERIFY_MSG( (noCData or noChildren), "Cannot have data AND children" ); //! Write CDATA if available (not indented) if ( not noCData ) { cData_ -> write( out ); out << "\n"; } //! Write children if available if ( not noChildren ) { for ( unsigned c = 0; c < children_.size(); c ++ ) children_[c].write( out, indentLevel+1 ); } //! write closing tag if their had been data or children if ( not( noChildren and noCData ) ) { out << indent << "</" << name_ << ">\n"; } }
void remap() { VERIFY(BlockSize != FileSize); if (MappedRegion) munmap(MappedRegion, BlockSize); BlockOffset += BlockSize; // We do not add PROT_WRITE here intentionaly - remapping and write access // is pretty error-prone. MappedRegion = (uint8_t*)mmap(NULL, BlockSize, PROT_READ, MAP_FILE | MAP_PRIVATE, StreamFile, BlockOffset); VERIFY_MSG((intptr_t)MappedRegion != -1L, "mmap(2) failed. Reason: " << strerror(errno) << ". Error code: " << errno); }
//------------------------------------------------------------------------------ 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; }
/** Compute the elastic (large!) deformation of a block of material. * See problem description in ref06::PulledSheetProblem for a the boundary * conditions. The problem is non-linear and therefore a Newton method is * used. Moreover, the applied load (displacement or traction) is divided into * load steps. * * New features: * - vectorial problem: DoFs are not scalar anymore * - hyper-elasticity * */ int ref06::compressible( int argc, char * argv[] ) { // basic attributes of the computation const unsigned geomDeg = 1; const unsigned fieldDeg = 2; const base::Shape shape = base::HyperCubeShape<SPACEDIM>::value; // typedef mat::hypel::StVenant Material; typedef mat::hypel::NeoHookeanCompressible Material; // usage message if ( argc != 3 ) { std::cout << "Usage: " << argv[0] << " mesh.smf input.dat \n"; return 0; } // read name of input file const std::string meshFile = boost::lexical_cast<std::string>( argv[1] ); const std::string inputFile = boost::lexical_cast<std::string>( argv[2] ); // read from input file double E, nu, pull, traction, tolerance; unsigned maxIter, loadSteps; bool dispControlled; { //Feed properties parser with the variables to be read base::io::PropertiesParser prop; prop.registerPropertiesVar( "E", E ); prop.registerPropertiesVar( "nu", nu ); prop.registerPropertiesVar( "pull", pull ); prop.registerPropertiesVar( "maxIter", maxIter ); prop.registerPropertiesVar( "loadSteps", loadSteps ); prop.registerPropertiesVar( "traction", traction ); prop.registerPropertiesVar( "dispControlled", dispControlled ); prop.registerPropertiesVar( "tolerance", tolerance ); // 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" ); } } // find base name from mesh file const std::string baseName = base::io::baseName( meshFile, ".smf" ); //-------------------------------------------------------------------------- // define a mesh typedef base::Unstructured<shape,geomDeg> Mesh; const unsigned dim = Mesh::Node::dim; // create a mesh and read from input Mesh mesh; { std::ifstream smf( meshFile.c_str() ); base::io::smf::readMesh( smf, mesh ); smf.close(); } // quadrature objects for volume and surface const unsigned kernelDegEstimate = 3; typedef base::Quadrature<kernelDegEstimate,shape> Quadrature; Quadrature quadrature; typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature; SurfaceQuadrature surfaceQuadrature; // Create a field const unsigned doFSize = dim; typedef base::fe::Basis<shape,fieldDeg> FEBasis; typedef base::Field<FEBasis,doFSize> Field; typedef Field::DegreeOfFreedom DoF; Field field; // generate DoFs from mesh base::dof::generate<FEBasis>( mesh, field ); // Creates a list of <Element,faceNo> pairs along the boundary base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); // Create a boundary mesh from this list typedef base::mesh::BoundaryMeshBinder<Mesh::Element>::Type BoundaryMesh; BoundaryMesh boundaryMesh; { // Create a real mesh object from this list base::mesh::generateBoundaryMesh( meshBoundary.begin(), meshBoundary.end(), mesh, boundaryMesh ); } // initial pull = (total amount) / (number of steps) const double firstPull = pull / static_cast<double>( loadSteps ); // constrain the boundary base::dof::constrainBoundary<FEBasis>( meshBoundary.begin(), meshBoundary.end(), mesh, field, boost::bind( &ref06::PulledSheet<dim>::dirichletBC<DoF>, _1, _2, dispControlled, firstPull ) ); // Bind the fields together typedef base::asmb::FieldBinder<Mesh,Field> FieldBinder; FieldBinder fieldBinder( mesh, field ); typedef FieldBinder::TupleBinder<1,1>::Type FTB; typedef base::asmb::SurfaceFieldBinder<BoundaryMesh,Field> SurfaceFieldBinder; SurfaceFieldBinder surfaceFieldBinder( boundaryMesh, field ); typedef SurfaceFieldBinder::TupleBinder<1>::Type SFTB; // material object Material material( mat::Lame::lambda( E, nu), mat::Lame::mu( E, nu ) ); // matrix kernel typedef solid::HyperElastic<Material,FTB::Tuple> HyperElastic; HyperElastic hyperElastic( material ); // Number the degrees of freedom const std::size_t numDofs = base::dof::numberDoFsConsecutively( field.doFsBegin(), field.doFsEnd() ); std::cout << "# Number of dofs " << numDofs << std::endl; // create table for writing the convergence behaviour of the nonlinear solves base::io::Table<4>::WidthArray widths = {{ 2, 5, 5, 15 }}; base::io::Table<4> table( widths ); table % "Step" % "Iter" % "|F|" % "|x|"; std::cout << "#" << table; // write a vtk file ref06::writeVTKFile( baseName, 0, mesh, field, material ); //-------------------------------------------------------------------------- // Loop over load steps //-------------------------------------------------------------------------- for ( unsigned step = 0; step < loadSteps; step++ ) { // rescale constraints in every load step: (newValue / oldValue) const double pullFactor = (step == 0 ? static_cast<double>( step+1 ) : static_cast<double>( step+1 )/ static_cast<double>(step) ); // scale constraints base::dof::scaleConstraints( field, pullFactor ); //---------------------------------------------------------------------- // Nonlinear iterations //---------------------------------------------------------------------- unsigned iter = 0; while ( iter < maxIter ) { table % step % iter; // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( numDofs ); // apply traction boundary condition, if problem is not disp controlled if ( not dispControlled ) { // value of applied traction const double tractionFactor = traction * static_cast<double>(step+1) / static_cast<double>( loadSteps ); // apply traction load base::asmb::neumannForceComputation<SFTB>( surfaceQuadrature, solver, surfaceFieldBinder, boost::bind( &ref06::PulledSheet<dim>::neumannBC, _1, _2, tractionFactor ) ); } // residual forces base::asmb::computeResidualForces<FTB>( quadrature, solver, fieldBinder, hyperElastic ); // Compute element stiffness matrices and assemble them base::asmb::stiffnessMatrixComputation<FTB>( quadrature, solver, fieldBinder, hyperElastic ); // Finalise assembly solver.finishAssembly(); // norm of residual const double conv1 = solver.norm(); table % conv1; // convergence via residual norm if ( conv1 < tolerance * E ) { // note the tolerance multiplier std::cout << table; break; } // Solve //solver.choleskySolve(); solver.cgSolve(); // distribute results back to dofs base::dof::addToDoFsFromSolver( solver, field ); // norm of displacement increment const double conv2 = solver.norm(); table % conv2; std::cout << table; iter++; // convergence via increment if ( conv2 < tolerance ) break; } // Finished non-linear iterations //---------------------------------------------------------------------- // warning if ( iter == maxIter ) { std::cout << "# (WW) Step " << step << " has not converged within " << maxIter << " iterations \n"; } // write a vtk file ref06::writeVTKFile( baseName, step+1, mesh, field, material ); } // Finished load steps //-------------------------------------------------------------------------- return 0; }
//------------------------------------------------------------------------------ int main( int argc, char * argv[] ) { // basic attributes of the computation const unsigned geomDeg = 1; const unsigned fieldDegU = 2; const unsigned fieldDegP = 1; const unsigned tiOrder = 2; // order of time integrator const base::Shape shape = base::QUAD; //typedef base::time::BDF<tiOrder> MSM; typedef base::time::AdamsMoulton<tiOrder> MSM; // time stepping method determines the history size const unsigned nHist = MSM::numSteps; const std::string inputFile = "terz.inp"; double E, nu, alpha, c0, k, H, F, tMax; unsigned numSteps, numIntervals; { base::io::PropertiesParser pp; pp.registerPropertiesVar( "E", E ); pp.registerPropertiesVar( "nu", nu ); pp.registerPropertiesVar( "alpha", alpha ); pp.registerPropertiesVar( "c0", c0 ); pp.registerPropertiesVar( "k", k ); pp.registerPropertiesVar( "H", H ); pp.registerPropertiesVar( "F", F ); pp.registerPropertiesVar( "tMax", tMax ); pp.registerPropertiesVar( "numSteps", numSteps ); pp.registerPropertiesVar( "numIntervals", numIntervals ); // Read variables from the input file std::ifstream inp( inputFile.c_str() ); VERIFY_MSG( inp.is_open(), "Cannot open input file" ); pp.readValues( inp ); inp.close( ); } const double deltaT = tMax / static_cast<double>( numSteps ); // usage message if ( argc != 2 ) { std::cout << "Usage: " << argv[0] << " mesh.smf \n"; return 0; } const std::string meshFile = boost::lexical_cast<std::string>( argv[1] ); // Analytic solution Terzaghi terzaghi( E, nu, alpha, c0, k, H, F ); //-------------------------------------------------------------------------- // define a mesh typedef base::Unstructured<shape,geomDeg> Mesh; const unsigned dim = Mesh::Node::dim; // create a mesh and read from input Mesh mesh; { std::ifstream smf( meshFile.c_str() ); base::io::smf::readMesh( smf, mesh ); smf.close(); } // quadrature objects for volume and surface const unsigned kernelDegEstimate = 3; typedef base::Quadrature<kernelDegEstimate,shape> Quadrature; Quadrature quadrature; typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature; SurfaceQuadrature surfaceQuadrature; // Create a displacement field const unsigned doFSizeU = dim; typedef base::fe::Basis<shape,fieldDegU> FEBasisU; typedef base::Field<FEBasisU,doFSizeU,nHist> Displacement; typedef Displacement::DegreeOfFreedom DoFU; Displacement displacement; // Create a pressure field const unsigned doFSizeP = 1; typedef base::fe::Basis<shape,fieldDegP> FEBasisP; typedef base::Field<FEBasisP,doFSizeP,nHist> Pressure; typedef Pressure::DegreeOfFreedom DoFP; Pressure pressure; // generate DoFs from mesh base::dof::generate<FEBasisU>( mesh, displacement ); base::dof::generate<FEBasisP>( mesh, pressure ); // Creates a list of <Element,faceNo> pairs along the boundary base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); // Create a boundary mesh from this list typedef base::mesh::CreateBoundaryMesh<Mesh::Element> CreateBoundaryMesh; typedef CreateBoundaryMesh::BoundaryMesh BoundaryMesh; BoundaryMesh boundaryMesh; { CreateBoundaryMesh::apply( meshBoundary.begin(), meshBoundary.end(), mesh, boundaryMesh ); } // material object typedef mat::hypel::StVenant Material; Material material( mat::Lame::lambda( E, nu), mat::Lame::mu( E, nu ) ); typedef base::asmb::FieldBinder<Mesh,Displacement,Pressure> Field; Field field( mesh, displacement, pressure ); typedef Field::TupleBinder<1,1>::Type TopLeft; typedef Field::TupleBinder<1,2>::Type TopRight; typedef Field::TupleBinder<2,1>::Type BotLeft; typedef Field::TupleBinder<2,2>::Type BotRight; // surface displacement field typedef base::asmb::SurfaceFieldBinder<BoundaryMesh,Displacement> SurfaceFieldBinder; SurfaceFieldBinder surfaceFieldBinder( boundaryMesh, displacement ); typedef SurfaceFieldBinder::TupleBinder<1>::Type SFTB; // kernel objects typedef solid::HyperElastic<Material,TopLeft::Tuple> HyperElastic; HyperElastic hyperElastic( material ); typedef fluid::PressureGradient<TopRight::Tuple> GradP; GradP gradP; //typedef fluid::VelocityDivergence<FieldPUUTuple> DivU; //DivU divU( true ); // * alpha typedef PoroDivU<BotLeft::Tuple> DivU; DivU divU( alpha ); typedef heat::Laplace<BotRight::Tuple> Laplace; Laplace laplace( k ); // constrain the boundary base::dof::constrainBoundary<FEBasisU>( meshBoundary.begin(), meshBoundary.end(), mesh, displacement, boost::bind( &dirichletU<dim,DoFU>, _1, _2, 1.0 ) ); base::dof::constrainBoundary<FEBasisP>( meshBoundary.begin(), meshBoundary.end(), mesh, pressure, boost::bind( &dirichletP<dim,DoFP>, _1, _2, H ) ); // Number the degrees of freedom const std::size_t numDoFsU = base::dof::numberDoFsConsecutively( displacement.doFsBegin(), displacement.doFsEnd() ); std::cout << "# Number of displacement dofs " << numDoFsU << std::endl; const std::size_t numDoFsP = base::dof::numberDoFsConsecutively( pressure.doFsBegin(), pressure.doFsEnd(), numDoFsU ); std::cout << "# Number of pressure dofs " << numDoFsP << std::endl; // write VTK file writeVTK( mesh, displacement, pressure, meshFile, 0 ); for ( unsigned n = 0; n < numSteps; n++ ) { const double time = (n+1) * deltaT; std::cout << time << " "; // initialise current displacement to zero (linear elasticity) std::for_each( displacement.doFsBegin(), displacement.doFsEnd(), boost::bind( &DoFU::clearValue, _1 ) ); // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( numDoFsU + numDoFsP ); //------------------------------------------------------------------ base::asmb::stiffnessMatrixComputation<TopLeft>( quadrature, solver, field, hyperElastic ); base::asmb::stiffnessMatrixComputation<TopRight>( quadrature, solver, field, gradP ); base::asmb::stiffnessMatrixComputation<BotRight>( quadrature, solver, field, laplace); // time integration terms base::time::computeReactionTerms<BotLeft,MSM>( divU, quadrature, solver, field, deltaT, n ); base::time::computeInertiaTerms<BotRight,MSM>( quadrature, solver, field, deltaT, n, c0 ); base::time::computeResidualForceHistory<BotRight,MSM>( laplace, quadrature, solver, field, n ); // Neumann boundary condition base::asmb::neumannForceComputation<SFTB>( surfaceQuadrature, solver, surfaceFieldBinder, boost::bind( &neumannBC<dim>, _1, _2, H, F ) ); // Finalise assembly solver.finishAssembly(); // Solve solver.superLUSolve(); // distribute results back to dofs base::dof::setDoFsFromSolver( solver, displacement ); base::dof::setDoFsFromSolver( solver, pressure ); // push history std::for_each( displacement.doFsBegin(), displacement.doFsEnd(), boost::bind( &DoFU::pushHistory, _1 ) ); std::for_each( pressure.doFsBegin(), pressure.doFsEnd(), boost::bind( &DoFP::pushHistory, _1 ) ); // write VTK file writeVTK( mesh, displacement, pressure, meshFile, n+1 ); // Finished time steps //-------------------------------------------------------------------------- const std::pair<double,double> approx = probe( mesh, displacement, pressure ); const double p = terzaghi.pressure( H/2., time ); const double u = terzaghi.displacement( H/2., time ); std::cout << u << " " << approx.first << " " << p << " " << approx.second << '\n'; } return 0; }
//------------------------------------------------------------------------------ int main( int argc, char * argv[] ) { // basic attributes of the computation const unsigned geomDeg = 1; const unsigned fieldDeg = 1; const unsigned dim = 2; const base::Shape shape = base::SimplexShape<dim-1>::value; // usage message if ( argc != 2 ) { std::cout << "Usage: " << argv[0] << " input.dat \n"; return 0; } // read name of input file const std::string inputFile = boost::lexical_cast<std::string>( argv[1] ); // read from input file std::string meshFile; double A, B, tolerance, pressure; unsigned maxIter, loadSteps; { //Feed properties parser with the variables to be read base::io::PropertiesParser prop; prop.registerPropertiesVar( "meshFile", meshFile ); prop.registerPropertiesVar( "A", A ); prop.registerPropertiesVar( "B", B ); prop.registerPropertiesVar( "maxIter", maxIter ); prop.registerPropertiesVar( "loadSteps", loadSteps ); prop.registerPropertiesVar( "tolerance", tolerance ); prop.registerPropertiesVar( "pressure", pressure ); // 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" ); } } // find base name from mesh file const std::string baseName = base::io::baseName( meshFile, ".smf" ); //-------------------------------------------------------------------------- // define a mesh typedef base::Unstructured<shape,geomDeg,dim> Mesh; // create a mesh and read from input Mesh mesh; { std::ifstream smf( meshFile.c_str() ); base::io::smf::readMesh( smf, mesh ); smf.close(); } // quadrature objects for volume and surface const unsigned kernelDegEstimate = 1; //3; typedef base::Quadrature<kernelDegEstimate,shape> Quadrature; Quadrature quadrature; // Create a field const unsigned doFSize = dim; typedef base::fe::Basis<shape,fieldDeg> FEBasis; typedef base::Field<FEBasis,doFSize> Field; typedef Field::DegreeOfFreedom DoF; Field field; // generate DoFs from mesh base::dof::generate<FEBasis>( mesh, field ); // constrain a dof constrainSupports( field ); // Bind the fields together typedef base::asmb::FieldBinder<Mesh,Field> FieldBinder; FieldBinder fieldBinder( mesh, field ); typedef FieldBinder::TupleBinder<1,1>::Type FTB; // material object typedef surf::Skalak Energy; Energy energy( A, B ); //typedef surf::NeoHookean Energy; //Energy energy( A ); typedef surf::HyperElasticMembrane<Energy> Material; Material material( energy ); // matrix kernel typedef solid::HyperElastic<Material,FTB::Tuple> HyperElastic; HyperElastic hyperElastic( material ); // Number the degrees of freedom const std::size_t numDofs = base::dof::numberDoFsConsecutively( field.doFsBegin(), field.doFsEnd() ); std::cout << "# Number of dofs " << numDofs << std::endl; // write a vtk file writeVTKFile( baseName, 0, mesh, field, material ); // load increment const double deltaP = pressure / static_cast<double>( loadSteps ); std::cout << "# pressure radius \n" << 0.0 << " " << giveRadius( mesh, field ) << "\n"; //-------------------------------------------------------------------------- // Loop over load steps //-------------------------------------------------------------------------- for ( unsigned step = 0; step < loadSteps; step++ ) { // current load const double p = (step+1) * deltaP; //---------------------------------------------------------------------- // Nonlinear iterations //---------------------------------------------------------------------- unsigned iter = 0; while ( iter < maxIter ) { //std::cout << "Iter " << iter; // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( numDofs ); base::asmb::computeResidualForces<FTB>( quadrature, solver, fieldBinder, hyperElastic ); // Compute element stiffness matrices and assemble them base::asmb::stiffnessMatrixComputation<FTB>( quadrature, solver, fieldBinder, hyperElastic, iter > 0 ); // internal pressure load base::asmb::bodyForceComputation2<FTB>( quadrature, solver, fieldBinder, boost::bind( &internalPressure<Mesh::Element>, _1, _2, p ) ); // Finalise assembly solver.finishAssembly(); // norm of residual const double conv1 = solver.norm(); //std::cout << " |F| = " << conv1; // convergence via residual norm if ( conv1 < tolerance * A ) { // note the tolerance multiplier //std::cout << "\n"; break; } // Solve solver.choleskySolve(); // distribute results back to dofs base::dof::addToDoFsFromSolver( solver, field ); // norm of displacement increment const double conv2 = solver.norm(); //std::cout << " | DU | = " << conv2 << "\n"; // convergence via increment if ( conv2 < tolerance ) break; iter++; } // Finished non-linear iterations //---------------------------------------------------------------------- // warning if ( iter == maxIter ) { std::cout << "# (WW) Step " << step << " has not converged within " << maxIter << " iterations \n"; } // write a vtk file writeVTKFile( baseName, step+1, mesh, field, material ); std::cout << p << " " << giveRadius( mesh, field ) << std::endl; } // Finished load steps //-------------------------------------------------------------------------- return 0; }
void operator()( const Grid & grid, const unsigned dir, const bool begin, SurfaceMesh & surfaceMesh ) const { //! Sanity check of direction VERIFY_MSG( (dir < Grid::dim), "Input argument for direction wrong" ); //! Dimensions of the grid const MultiIndexType gridSizes = grid.gridSizes(); //! Multi-index component to compare with const int mIndexComp = ( begin == false ? 0 : gridSizes[dir]-1 ); //! Number of elements in the structured grid const std::size_t numElements = MultiIndex::length( gridSizes ); //! Number of elements on the requested surface const std::size_t numElementsOnSurface = numElements / gridSizes[ dir ]; //! Construct parametric geometry of the element const unsigned surfaceID = detail_::convertToSurfaceID<VolumeElement::shape>( dir, begin ); //! List of indices of the parameter space vertices which form the surface typename ParameterSurface::Surface parameterSurfaceIndices = ParameterSurface::surfaceTable[ surfaceID ]; //! Interpolation points of the surface shape function boost::array< typename SurfaceShapeFun::VecDim, SurfaceShapeFun::numFun> surfaceSupportPoints; SurfaceShapeFun::supportPoints( surfaceSupportPoints ); //! Vertices of the parameter volume boost::array< typename LinearVolumeFun::VecDim, LinearVolumeFun::numFun> volumeVertices; LinearVolumeFun::supportPoints( volumeVertices ); // --> Reorder for hiearchical ordering // Then, the object ParameterFaces< shape, dim-1> can be used and // ParamaterSurface discarded. //! Iterator to surface mesh elements typename SurfaceMesh::ElementPtrIter surfElemIter = surfaceMesh.elementsBegin(); //! Linear shape function on the surface simplex LinearSimplexFun linearSimplexFun; //! Hexahedra will have two triangles per face const unsigned numSurfElementsPerElement = detail_::NumSimplicesPerElementSurface<VolumeElement::shape>::value; //! Temporary storage of surface elements and nodes std::vector<SurfaceElement*> surfaceElements; surfaceElements.reserve( numElementsOnSurface * numSurfElementsPerElement ); std::vector<SurfaceNode*> surfaceNodes; //! node counter std::size_t nodeCtr = 0; //! Go through all elements for ( std::size_t e = 0; e < numElements; e ++ ) { //! Construct multi-index from linear counter const MultiIndexType eM = MultiIndex::wrap( e, gridSizes ); //! Check if on requested boundary surface const bool onBoundary = ( eM[ dir ] == mIndexComp ); //! If so, construct the surface element(s) if ( onBoundary ) { //! Get pointer to volume element VolumeElement * vep = grid.elementPtr( eM ); //! Go through elements on the surface of the volume element for ( unsigned se = 0; se < numSurfElementsPerElement; se ++ ) { //! Create new surface element SurfaceElement * surfElem = new SurfaceElement; //! Extract the surface simplex's vertices boost::array<unsigned, numSurfSimplexVertices> surfSimplex; detail_::ExtractSurfaceSimplex<VolumeElement::shape>()( parameterSurfaceIndices, se, surfSimplex ); //! Set volume element pointer surfElem -> setVolumeElementPointer( vep ); //! Access to surface elements geometry nodes typename SurfaceElement::NodePtrIter nodePtrIter = surfElem -> nodesBegin(); //! Go through the parameter points of the surface element typename SurfaceElement::ParamIter paramIter = surfElem -> parametricBegin(); typename SurfaceElement::ParamIter paramEnd = surfElem -> parametricEnd(); for ( unsigned p = 0; paramIter != paramEnd; ++paramIter, ++nodePtrIter, p++ ) { //! .. typename base::Vector<surfaceDim>::Type eta = surfaceSupportPoints[ p ]; typename LinearSimplexFun::FunArray phi; linearSimplexFun.evaluate( eta, phi ); typename base::Vector<volumeDim>::Type xi = base::constantVector<volumeDim>( 0. ); for ( unsigned s = 0; s < phi.size(); s ++ ) { xi += phi[s] * volumeVertices[ surfSimplex[s] ]; } *paramIter = xi; //! evaluate geometry at the parameter point const typename VolumeElement::Node::VecDim x = base::Geometry<VolumeElement>()( vep, xi ); //! convert to vector and pass to node std::vector<double> xV( x.size() ); for ( int d = 0; d < x.size(); d ++ ) xV[d] = x[d]; SurfaceNode * surfNode = new SurfaceNode; surfNode -> setX( xV.begin() ); surfNode -> setID( nodeCtr++ ); *nodePtrIter = surfNode; surfaceNodes.push_back( surfNode ); } // end loop over surface element's nodes //! Store element pointer surfaceElements.push_back( surfElem ); } // end loop over simplices per volume element } // end condition if volume element lies on requested bdry }// end loop over all volume elements surfaceMesh.allocate( surfaceNodes.size(), surfaceElements.size() ); std::copy( surfaceNodes.begin(), surfaceNodes.end(), surfaceMesh.nodesBegin() ); std::copy( surfaceElements.begin(), surfaceElements.end(), surfaceMesh.elementsBegin() ); return; }
/** Analysis of a CSG-modelled geometry (elasticity) */ int cutCell::csgElastic( int argc, char* argv[] ) { // spatial dimension const unsigned dim = 3; typedef base::Vector<dim,double>::Type VecDim; //-------------------------------------------------------------------------- // surfaces // sphere const double rs = 0.65; const VecDim cs = base::constantVector<dim>( 0.5 ); base::cut::Sphere<dim> sphere( rs, cs, true ); // cylinder const double rc = 0.3; const VecDim cc = cs; const VecDim zero = base::constantVector<dim>(0.); VecDim e1 = zero; e1[0] = 1.; VecDim e2 = zero; e2[1] = 1.; VecDim e3 = zero; e3[2] = 1.; base::cut::Cylinder<dim> cyl1( rc, cc, e1, false ); base::cut::Cylinder<dim> cyl2( rc, cc, e2, false ); base::cut::Cylinder<dim> cyl3( rc, cc, e3, false ); if ( argc != 3 ) { std::cerr << "Usage: " << argv[0] << " N input.dat\n" << "(Compiled for dim=" << dim << ")\n\n"; return -1; } // read name of input file const unsigned numElements = boost::lexical_cast<unsigned>( argv[1] ); const std::string inputFile = boost::lexical_cast<std::string>( argv[2] ); // read from input file double E, nu, xmax, cutThreshold, sX, sY, sZ; std::string meshFile; unsigned stabilise; // 0 - not, 1 - Höllig bool compute; unsigned maxIter, loadSteps; double tolerance, forceVal; { //Feed properties parser with the variables to be read base::io::PropertiesParser prop; prop.registerPropertiesVar( "E", E ); prop.registerPropertiesVar( "nu", nu ); prop.registerPropertiesVar( "xmax", xmax ); prop.registerPropertiesVar( "sX", sX ); prop.registerPropertiesVar( "sY", sY ); prop.registerPropertiesVar( "sZ", sZ ); prop.registerPropertiesVar( "stabilise", stabilise ); prop.registerPropertiesVar( "meshFile", meshFile ); prop.registerPropertiesVar( "compute", compute ); prop.registerPropertiesVar( "cutThreshold", cutThreshold ); prop.registerPropertiesVar( "maxIter", maxIter ); prop.registerPropertiesVar( "tolerance", tolerance ); prop.registerPropertiesVar( "loadSteps", loadSteps ); prop.registerPropertiesVar( "forceVal", forceVal ); // Read variables from the input file std::ifstream inp( inputFile.c_str() ); VERIFY_MSG( inp.is_open(), "Cannot open input file" ); VERIFY_MSG( prop.readValuesAndCheck( inp ), "Input error" ); inp.close( ); } // in case of no computation, do not stabilise if ( not compute ) stabilise = 0; // basic attributes of the computation const unsigned geomDeg = 1; const unsigned fieldDeg = 1; const base::Shape shape = //base::SimplexShape<dim>::value; base::HyperCubeShape<dim>::value; const base::Shape surfShape = base::SimplexShape<dim-1>::value; const unsigned kernelDegEstimate = 5; // Bulk mesh typedef base::Unstructured<shape,geomDeg> Mesh; typedef Mesh::Node::VecDim VecDim; Mesh mesh; std::string baseName; VecDim a, b; for ( unsigned d = 0; d < dim; d++ ) { a[d] = 0.; b[d] = xmax; } base::auxi::BoundingBox<dim> bbox( a, b ); if ( numElements > 0 ) { base::Vector<dim,unsigned>::Type N; for ( unsigned d = 0; d < dim; d++ ) { N[d] = numElements; } generateMesh<dim>( mesh, N, a, b ); baseName = argv[0] + std::string(".") + base::io::leadingZeros( numElements ); } else{ std::ifstream smf( meshFile.c_str() ); base::io::smf::readMesh( smf, mesh ); baseName = base::io::baseName( meshFile, ".smf" ); } // Boundary mesh typedef base::mesh::BoundaryMeshBinder<Mesh,true>::Type BoundaryMesh; BoundaryMesh boundaryMesh; base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); base::mesh::generateBoundaryMesh( meshBoundary.begin(), meshBoundary.end(), mesh, boundaryMesh ); // Cell structures typedef base::cut::Cell<shape> Cell; std::vector<Cell> cells; typedef base::cut::Cell<surfShape> SurfCell; std::vector<SurfCell> surfCells; // intersection of all level sets typedef base::cut::LevelSet<dim> LevelSet; std::vector<LevelSet> levelSetIntersection; //-------------------------------------------------------------------------- // go through immersed surfaces //ImplicitGeometry<Mesh> geometry( mesh, boundaryMesh, sphere ); cutCell::ImplicitGeometry<Mesh> geometry( mesh, boundaryMesh ); geometry.intersectAnalytical( sphere, cutThreshold ); geometry.intersectAnalytical( cyl1, cutThreshold ); geometry.intersectAnalytical( cyl2, cutThreshold ); geometry.intersectAnalytical( cyl3, cutThreshold ); levelSetIntersection = geometry.getLevelSet(); #ifdef EMBEDFIRST cells = geometry.getCells(); surfCells = geometry.getSurfCells(); #else base::cut::generateCutCells( mesh, levelSetIntersection, cells, base::cut::CREATE ); base::cut::generateCutCells( boundaryMesh, levelSetIntersection, surfCells, base::cut::CREATE ); #endif // Generate a mesh from the immersed surface typedef base::cut::SurfaceMeshBinder<Mesh>::SurfaceMesh SurfaceMesh; SurfaceMesh surfaceMesh; base::cut::generateSurfaceMesh<Mesh,Cell>( mesh, cells, surfaceMesh ); //-------------------------------------------------------------------------- // FE #ifdef LINEAR typedef mat::hypel::StVenant Material; #else typedef mat::hypel::NeoHookeanCompressible Material; #endif typedef cutCell::HyperElastic<Mesh,Material,fieldDeg> HyperElastic; HyperElastic hyperElastic( mesh, E, nu ); typedef cutCell::SurfaceField<SurfaceMesh,HyperElastic::Field> SurfaceField; SurfaceField surfaceField( surfaceMesh, hyperElastic.getField() ); SurfaceField boundaryField( boundaryMesh, hyperElastic.getField() ); //-------------------------------------------------------------------------- // Quadratures typedef base::cut::Quadrature<kernelDegEstimate,shape> CutQuadrature; CutQuadrature cutQuadrature( cells, true ); typedef base::Quadrature<kernelDegEstimate,surfShape> SurfaceQuadrature; SurfaceQuadrature surfaceQuadrature; typedef base::cut::Quadrature<kernelDegEstimate,surfShape> SurfaceCutQuadrature; SurfaceCutQuadrature surfaceCutQuadrature( surfCells, true ); // compute supports const std::size_t numDoFs = std::distance( hyperElastic.getField().doFsBegin(), hyperElastic.getField().doFsEnd() ); std::vector<double> supports; supports.resize( numDoFs ); base::cut::supportComputation( mesh, hyperElastic.getField(), cutQuadrature, supports ); std::vector<std::pair<std::size_t,VecDim> > doFLocation; base::dof::associateLocation( hyperElastic.getField(), doFLocation ); // Fundamental solution #ifdef LINEAR HyperElastic::VecDim sourcePoint = base::constantVector<dim>( 0. ); HyperElastic::VecDim pointForce = base::constantVector<dim>( 0. ); sourcePoint[0] = sX; pointForce[0] = 1.; if ( dim > 1 ) { sourcePoint[1] = sY; pointForce[1] = 2.; } if ( dim > 2 ) { sourcePoint[2] = sZ; pointForce[2] = 3.; } typedef base::auxi::FundSolElastoStatic<dim> FSol; FSol fSol( mat::Lame::lambda( E, nu ), mat::Lame::mu( E, nu ) ); typedef boost::function< HyperElastic::VecDoF( const VecDim& ) > FFun; FFun fFun = boost::bind( &FSol::fun, &fSol, _1, sourcePoint, pointForce ); // apply dirichlet constraints base::dof::constrainBoundary<HyperElastic::FEBasis>( meshBoundary.begin(), meshBoundary.end(), mesh, hyperElastic.getField(), boost::bind( &dirichletBCFromFSol<FFun,HyperElastic::DoF>, _1, _2, fFun ) ); typedef boost::function< HyperElastic::VecDoF( const VecDim&, const VecDim&) > FFun2; FFun2 fFun2 = boost::bind( &FSol::coNormal, &fSol, _1, sourcePoint, pointForce, _2 ); #else base::dof::constrainBoundary<HyperElastic::FEBasis>( meshBoundary.begin(), meshBoundary.end(), mesh, hyperElastic.getField(), boost::bind( &fixBottom<dim,HyperElastic::DoF>, _1, _2, bbox ) ); #endif base::cut::stabiliseBasis( mesh, hyperElastic.getField(), supports, doFLocation ); // number DoFs const std::size_t activeDoFsU = base::dof::numberDoFsConsecutively( hyperElastic.getField().doFsBegin(), hyperElastic.getField().doFsEnd() ); //-------------------------------------------------------------------------- // Load step loop #ifdef LINEAR const unsigned numSteps = 1; const unsigned numIter = 1; #else const unsigned numSteps = loadSteps; const unsigned numIter = maxIter; // write zero state hyperElastic.writeVTKFile( baseName, 0, levelSetIntersection, cells, true ); hyperElastic.writeVTKFileCut( baseName, 0, levelSetIntersection, cells, true ); #endif for ( unsigned s = 0; s < numSteps and compute; s++ ) { //---------------------------------------------------------------------- // Nonlinear iterations unsigned iter = 0; while( iter < numIter ) { // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( activeDoFsU ); #ifdef LINEAR // Neumann boundary condition -- box boundary boundaryField.applyNeumannBoundaryConditions( surfaceCutQuadrature, solver, fFun2 ); // Neumann boundary condition -- immersed surface surfaceField.applyNeumannBoundaryConditions( surfaceQuadrature, solver, fFun2 ); #else const double factor = static_cast<double>( s+1 ) / static_cast<double>( numSteps ); boundaryField.applyNeumannBoundaryConditions( surfaceCutQuadrature, solver, boost::bind( &twistTop<dim>, _1, _2, bbox, forceVal * factor ) ); #endif hyperElastic.assembleBulk( cutQuadrature, solver, iter ); // Finalise assembly solver.finishAssembly(); // norm of residual const double conv1 = solver.norm(); #ifndef LINEAR std::cout << s << " " << iter << " " << conv1 << " "; #endif // convergence via residual norm if ( conv1 < tolerance * E ) { // note the tolerance multiplier #ifndef LINEAR std::cout << std::endl; #endif break; } // Solve //solver.choleskySolve(); //solver.cgSolve(); solver.superLUSolve(); // distribute results back to dofs base::dof::addToDoFsFromSolver( solver, hyperElastic.getField() ); // norm of displacement increment const double conv2 = solver.norm(); #ifndef LINEAR std::cout << conv2 << std::endl; #endif iter++; // convergence via increment if ( conv2 < tolerance ) break; } // end iterations // warning if ( iter == maxIter ) { std::cout << "# (WW) Step " << s << " has not converged within " << maxIter << " iterations \n"; } //---------------------------------------------------------------------- // write a vtk file hyperElastic.writeVTKFile( baseName, s+1, levelSetIntersection, cells ); hyperElastic.writeVTKFileCut( baseName, s+1, levelSetIntersection, cells ); } // end load steps //------------------------------------------------------------------------------ // Compute error and mesh volume for convergence (linear only) #ifdef LINEAR double hmin; { std::vector<double> h; Mesh::ElementPtrConstIter eIter = mesh.elementsBegin(); Mesh::ElementPtrConstIter eEnd = mesh.elementsEnd(); for ( ; eIter != eEnd; ++eIter ) { h.push_back( base::mesh::elementSize( *eIter ) ); } hmin = *std::min_element( h.begin(), h.end() ); } std::cout << hmin << " "; //-------------------------------------------------------------------------- // Error std::cout << hyperElastic.computeL2Error( cutQuadrature, fFun ) << " "; //-------------------------------------------------------------------------- // Compute mesh volume const double volume = hyperElastic.computeVolume( cutQuadrature ); std::cout << std::abs(volume-exactV) << " "; //-------------------------------------------------------------------------- // Compute surface area double area = surfaceField.computeArea( surfaceQuadrature ); area += boundaryField.computeArea( surfaceCutQuadrature ); std::cout << std::abs(area-exactA) << " " << std::endl; #endif return 0; }
//------------------------------------------------------------------------------ int main( int argc, char * argv[] ) { // spatial dimension const unsigned dim = 2; // basic attributes of the computation const unsigned geomDeg = 1; const unsigned fieldDeg = 1; const base::Shape shape = base::HyperCubeShape<dim>::value; const unsigned kernelDegEstimate = 3; // usage message if ( argc != 3 ) { std::cout << "Usage: " << argv[0] << " mesh.smf input.dat \n" << "Compiled for dim=" << dim << "\n\n"; return 0; } // read name of input file const std::string meshFile = boost::lexical_cast<std::string>( argv[1] ); const std::string inputFile = boost::lexical_cast<std::string>( argv[2] ); // read from input file double E, nu, ubar1, ubar2, ubar3, tolerance; unsigned maxIter; { //Feed properties parser with the variables to be read base::io::PropertiesParser prop; prop.registerPropertiesVar( "E", E ); prop.registerPropertiesVar( "nu", nu ); prop.registerPropertiesVar( "ubar1", ubar1 ); prop.registerPropertiesVar( "ubar2", ubar2 ); prop.registerPropertiesVar( "ubar3", ubar3 ); prop.registerPropertiesVar( "maxIter", maxIter ); prop.registerPropertiesVar( "tolerance", tolerance ); // Read variables from the input file std::ifstream inp( inputFile.c_str() ); VERIFY_MSG( inp.is_open(), "Cannot open input file" ); prop.readValuesAndCheck( inp ); inp.close( ); } // find base name from mesh file const std::string baseName = "euler"; const double lambda = mat::Lame::lambda( E, nu ); const double mu = mat::Lame::mu( E, nu ); boost::array<double,dim> ubar; { const boost::array<double,3> aux = {{ ubar1, ubar2, ubar3 }}; for ( unsigned d = 0; d < dim; d++ ) ubar[d] = aux[d]; } const AnalyticEulerTensor<dim> analyticEuler( lambda, mu, ubar ); //-------------------------------------------------------------------------- // Create a mesh typedef base::Unstructured<shape,geomDeg> Mesh; Mesh mesh; { std::ifstream smf( meshFile.c_str() ); base::io::smf::readMesh( smf, mesh ); } // quadrature objects for volume and surface typedef base::Quadrature<kernelDegEstimate,shape> Quadrature; Quadrature quadrature; // Create a field const unsigned doFSize = dim; typedef base::fe::Basis<shape,fieldDeg> FEBasis; typedef base::Field<FEBasis,doFSize> Field; typedef Field::DegreeOfFreedom DoF; Field displacement; // generate DoFs from mesh base::dof::generate<FEBasis>( mesh, displacement ); // constrain the boundary { base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); base::dof::constrainBoundary<FEBasis>( meshBoundary.begin(), meshBoundary.end(), mesh, displacement, boost::bind( &dirichletBC<dim, Field::DegreeOfFreedom>, _1, _2 ) ); } // Bind the fields together typedef base::asmb::FieldBinder<Mesh,Field> FieldBinder; FieldBinder fieldBinder( mesh, displacement ); typedef FieldBinder::TupleBinder<1,1>::Type FTB; // matrix kernel typedef mat::hypel::NeoHookeanCompressible Material; Material material( lambda, mu ); typedef HyperElasticEuler<Material,FTB::Tuple> HyperElastic; HyperElastic hyperElastic( material ); // Number the degrees of freedom const std::size_t numDofs = base::dof::numberDoFsConsecutively( displacement.doFsBegin(), displacement.doFsEnd() ); std::cout << "# Number of dofs " << numDofs << std::endl; // write a vtk file writeVTKFile( baseName, 0, mesh, displacement ); //---------------------------------------------------------------------- // Nonlinear iterations //---------------------------------------------------------------------- unsigned iter = 0; while ( iter < maxIter ) { std::cout << iter << " "; // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( numDofs ); // Residual forces base::asmb::computeResidualForces<FTB>( quadrature, solver, fieldBinder, hyperElastic ); // Compute element stiffness matrices and assemble them base::asmb::stiffnessMatrixComputation<FTB>( quadrature, solver, fieldBinder, hyperElastic, iter > 0 ); // Body force base::asmb::bodyForceComputation<FTB>( quadrature, solver, fieldBinder, boost::bind( &AnalyticEulerTensor<dim>::force, &analyticEuler, _1 ) ); // Finalise assembly solver.finishAssembly(); // norm of residual const double conv1 = solver.norm(); std::cout << conv1 << " "; // convergence via residual norm if ( conv1 < tolerance * E ) { // note the tolerance multiplier std::cout << std::endl; break; } // Solve //solver.choleskySolve(); solver.superLUSolve(); // distribute results back to dofs base::dof::addToDoFsFromSolver( solver, displacement, iter > 0 ); // write a vtk file writeVTKFile( baseName, iter+1, mesh, displacement ); // norm of displacement increment const double conv2 = solver.norm(); std::cout << conv2 << std::endl; iter++; // convergence via increment if ( conv2 < tolerance ) break; } // Finished non-linear iterations //---------------------------------------------------------------------- // warning if ( iter == maxIter ) { std::cout << "# (WW) Solution has not converged within " << maxIter << " iterations \n"; } // Finished load steps //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // compute L2-error std::cout << "L2-error = " << base::post::errorComputation<0>( quadrature, mesh, displacement, boost::bind( &AnalyticEulerTensor<dim>::solution, &analyticEuler, _1 ) ) << '\n'; return 0; }