ImageBuf * SMF::getGrass() { ImageBuf * imageBuf = NULL; ImageSpec imageSpec( header.width / 4, header.length / 4, 1, TypeDesc::UINT8 ); unsigned char *data = new unsigned char[ imageSpec.image_pixels() ]; ifstream smf( loadFile.c_str() ); if( smf.good() ) { smf.seekg(80); int offset; SMFEH extraHeader; SMFEHGrass grassHeader; for(int i = 0; i < header.nExtraHeaders; ++i ) { offset = smf.tellg(); smf.read( (char *)&extraHeader, sizeof(SMFEH) ); smf.seekg(offset); if(extraHeader.type == 1) { smf.read( (char *)&grassHeader, sizeof(SMFEHGrass)); } smf.seekg( offset + extraHeader.size); } smf.seekg(grassHeader.grassPtr); smf.read( (char *)data, imageSpec.image_bytes() ); imageBuf = new ImageBuf( "grass", imageSpec, data ); } smf.close(); return imageBuf; }
TEST_F(SMFTrackTest, pause) { SMF smf(song_); SMFTrack t(smf); t.setup(MTRK_00, sizeof MTRK_00 - 1); EXPECT_EQ(false, t.is_playing()); EXPECT_EQ(false, t.is_paused()); t.pause(); EXPECT_EQ(false, t.is_playing()); EXPECT_EQ(true, t.is_paused()); t.update(); EXPECT_EQ(false, t.is_playing()); EXPECT_EQ(true, t.is_paused()); t.play(); EXPECT_EQ(true, t.is_playing()); EXPECT_EQ(true, t.is_paused()); t.update(); EXPECT_EQ(true, t.is_playing()); EXPECT_EQ(true, t.is_paused()); t.resume(); EXPECT_EQ(true, t.is_playing()); EXPECT_EQ(false, t.is_paused()); t.update(); EXPECT_EQ(false, t.is_playing()); EXPECT_EQ(false, t.is_paused()); }
bool SMF::saveFeatures() { if( verbose )cout << "INFO: saveFeatures\n"; char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); fstream smf(filename, ios::binary | ios::in | ios::out); smf.seekp(featuresPtr); int nTypes = featureTypes.size(); smf.write( (char *)&nTypes, 4); //featuretypes int nFeatures = features.size(); smf.write( (char *)&nFeatures, sizeof(nFeatures)); //numfeatures if( verbose ) printf( " %i features, %i types.\n", nFeatures, nTypes); for(unsigned int i = 0; i < featureTypes.size(); ++i ) { smf.write(featureTypes[i].c_str(), featureTypes[i].size() + 1 ); } for(unsigned int i = 0; i < features.size(); ++i ) { smf.write( (char *)&features[i], sizeof(SMFFeature) ); } smf.write( "\0", sizeof("\0")); smf.close(); return false; }
TEST_F(SMFTrackTest, setup) { SMF smf(song_); SMFTrack t(smf); EXPECT_EQ(true, t.setup(MTRK_00, sizeof MTRK_00 - 1)); EXPECT_EQ(false, t.setup("ABCDEFG", 7)); EXPECT_EQ(false, t.setup("ABCDEFGH", 8)); EXPECT_EQ(false, t.setup("MTrk\x00\x00\x10\x00", 8)); }
/** Read smf formatted file, create a temporary mesh and write a vtk file */ int main( int argc, char * argv[] ) { namespace smf2vtk = tools::converter::smf2vtk; namespace smf2xx = tools::converter::smf2xx; // Sanity check of the number of input arguments if ( argc != 2 ) { std::cout << "Usage: " << argv[0] << " file.smf \n\n"; return 0; } // Name of smf input file, its basename and the vtk output file name const std::string smfFile = boost::lexical_cast<std::string>( argv[1] ); const std::string base = smfFile.substr(0, smfFile.find( ".smf") ); const std::string vtkFile = base + ".vtk"; // Element attributes base::Shape elementShape; unsigned elementNumPoints; { // extract data from header std::ifstream smf( smfFile.c_str() ); smf2xx::readSMFHeader( smf, elementShape, elementNumPoints ); smf.close(); } // Input and output file streams std::ifstream smf( smfFile.c_str() ); std::ofstream vtk( vtkFile.c_str() ); // Call generic conversion helper smf2xx::Conversion< smf2vtk::Converter >::apply( elementShape, elementNumPoints, smf, vtk ); // Close the streams smf.close(); vtk.close(); return 0; }
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 ); } }
TEST_F(SMFTrackTest, play) { SMF smf(song_); SMFTrack t(smf); t.setup(MTRK_01, sizeof MTRK_01 - 1); EXPECT_EQ(false, t.is_playing()); t.play(); EXPECT_EQ(true, t.is_playing()); for (int i = 0; i < 6; ++i) { t.update(); EXPECT_EQ(true, t.is_playing()); } t.update(); EXPECT_EQ(false, t.is_playing()); }
ImageBuf * SMF::getHeight() { ImageBuf *imageBuf = NULL; ImageSpec imageSpec( header.width + 1, header.length + 1, 1, TypeDesc::UINT16 ); unsigned short *data = new unsigned short[ imageSpec.image_pixels() ]; ifstream smf( loadFile.c_str() ); if( smf.good() ) { smf.seekg(header.heightPtr); smf.read( (char *)data, imageSpec.image_bytes() ); imageBuf = new ImageBuf( "height", imageSpec, data); } smf.close(); return imageBuf; }
ImageBuf * SMF::getMetal() { ImageBuf * imageBuf = NULL; ImageSpec imageSpec( header.width / 2, header.length / 2, 1, TypeDesc::UINT8 ); unsigned char *data = new unsigned char[ imageSpec.image_pixels() ]; ifstream smf( loadFile.c_str() ); if( smf.good() ) { smf.seekg( header.metalPtr ); smf.read( (char *)data, imageSpec.image_bytes() ); imageBuf = new ImageBuf( "metal", imageSpec, data ); } smf.close(); return imageBuf; }
bool is_smf(string filename) { char magic[16]; // Perform tests for file validity ifstream smf(filename.c_str(), ifstream::in); if( smf.good() ) { smf.read( magic, 16); // perform test for file format if( !strcmp(magic, "spring map file") ) { smf.close(); return true; } } return false; }
// create a mesh and read from input Solid( const std::string meshFile, const double E, const double nu ) : E_( E ), material_( mat::Lame::lambda( E, nu), mat::Lame::mu( E, nu ) ), hyperElasticSpatial_( material_ ), hyperElasticMaterial_( material_ ), fieldBinder_( mesh_, current_ ) { std::ifstream smf( meshFile.c_str() ); base::io::smf::readMesh( smf, mesh_ ); smf.close(); // generate DoFs from mesh base::dof::generate<FEBasis>( mesh_, current_ ); solid::initialiseGeometry( mesh_, current_ ); }
ImageBuf * SMF::getMinimap() { ImageBuf * imageBuf = NULL; ImageSpec imageSpec( 1024, 1024, 4, TypeDesc::UINT8 ); unsigned char *data; ifstream smf( loadFile.c_str() ); if( smf.good() ) { unsigned char *temp = new unsigned char[MINIMAP_SIZE]; smf.seekg( header.minimapPtr ); smf.read( (char *)temp, MINIMAP_SIZE); data = dxt1_load(temp, 1024, 1024); delete [] temp; imageBuf = new ImageBuf( "minimap", imageSpec, data ); } smf.close(); return imageBuf; }
TEST_F(SMFTrackTest, inspect) { SMF smf(song_); SMFTrack t(smf); EXPECT_EQ(std::string("#<SMFTrack NONE>"), t.inspect()); t.setup(MTRK_01, sizeof MTRK_01 - 1); EXPECT_EQ(std::string("#<SMFTrack INITIALIZED>"), t.inspect()); t.play(); EXPECT_EQ(std::string("#<SMFTrack PLAYING>"), t.inspect()); t.pause(); EXPECT_EQ(std::string("#<SMFTrack PLAYING PAUSED>"), t.inspect()); t.update(); EXPECT_EQ(std::string("#<SMFTrack PLAYING PAUSED>"), t.inspect()); t.resume(); EXPECT_EQ(std::string("#<SMFTrack PLAYING>"), t.inspect()); t.update(); EXPECT_EQ(std::string("#<SMFTrack PLAYING>"), t.inspect()); t.stop(); EXPECT_EQ(std::string("#<SMFTrack STOPPED>"), t.inspect()); t.update(); EXPECT_EQ(std::string("#<SMFTrack STOPPED>"), t.inspect()); }
ImageBuf * SMF::getTilemap() { ImageBuf * imageBuf = NULL; ImageSpec imageSpec( header.width / 4, header.length / 4, 1, TypeDesc::UINT ); unsigned int *data = new unsigned int[ imageSpec.image_pixels() ]; ifstream smf( loadFile.c_str() ); if( smf.good() ) { smf.seekg( header.tilesPtr ); int numFiles = 0; smf.read( (char *)&numFiles, 4 ); smf.ignore( 4 ); for( int i = 0; i < numFiles; ++i ) { smf.ignore(4); smf.ignore(255, '\0'); } smf.read( (char *)data, imageSpec.image_bytes() ); imageBuf = new ImageBuf( "tilemap", imageSpec, data ); } smf.close(); return imageBuf; }
/** 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 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; }
//------------------------------------------------------------------------------ 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; }
bool SMF::decompileFeaturelist(int format = 0) { if( features.size() == 0) return true; if( verbose )cout << "INFO: Decompiling Feature List. " << header.featuresPtr << endl; char filename[256]; if(format == 0) sprintf( filename, "%s_featurelist.csv", outPrefix.c_str() ); else if (format == 1) sprintf( filename, "%s_featurelist.lua", outPrefix.c_str() ); ofstream outfile(filename); ifstream smf(loadFile.c_str(), ifstream::in); if( !smf.good() ) { return true; } smf.seekg( header.featuresPtr ); int nTypes; smf.read( (char *)&nTypes, 4); int nFeatures; smf.read( (char *)&nFeatures, 4); char name[256]; vector<string> featureNames; for( int i = 0; i < nTypes; ++i ) { smf.getline(name,255, '\0'); featureNames.push_back(name); } char line[1024]; SMFFeature feature; for( int i=0; i < nFeatures; ++i ) { // READ_SMFFEATURE(temp,&smf); smf.read( (char *)&feature, sizeof(SMFFeature) ); if(format == 0) { outfile << featureNames[feature.type] << ','; outfile << feature.x << ','; outfile << feature.y << ','; outfile << feature.z << ','; outfile << feature.r << ','; outfile << feature.s << endl; } else if (format == 1) { sprintf(line, "\t\t{ name = '%s', x = %i, z = %i, rot = \"%i\",},\n", featureNames[feature.type].c_str(), (int)feature.x, (int)feature.z, (int)feature.r * 32768 ); outfile << line; } } smf.close(); outfile.close(); return false; }
bool SMF::saveMinimap() { if( verbose )cout << "INFO: saveMinimap\n"; char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); fstream smf(filename, ios::binary | ios::in | ios::out); smf.seekp(minimapPtr); unsigned char *pixels; if( is_smf(minimapFile) ) { // Copy from SMF pixels = new unsigned char[MINIMAP_SIZE]; ifstream inFile(minimapFile.c_str(), ifstream::in); inFile.seekg(header.minimapPtr); inFile.read( (char *)pixels, MINIMAP_SIZE); inFile.close(); smf.write( (char *)pixels, MINIMAP_SIZE); smf.close(); delete [] pixels; return false; } //OpenImageIO ROI roi( 0, 1024, 0, 1024, 0, 1, 0, 4); ImageSpec imageSpec( roi.xend, roi.yend, roi.chend, TypeDesc::UINT8 ); // Load image file ImageBuf *imageBuf = new ImageBuf( minimapFile ); imageBuf->read( 0, 0, false, TypeDesc::UINT8 ); //FIXME attempt to generate minimap from tile files. if( !imageBuf->initialized() ) { // Create from height imageBuf->reset( minimapFile ); imageBuf->read( 0, 0, false, TypeDesc::UINT8 ); } if( !imageBuf->initialized() ) { // Create blank imageBuf->reset( "minimap", imageSpec); } imageSpec = imageBuf->specmod(); ImageBuf fixBuf; // Fix channels if( imageSpec.nchannels != roi.chend ) { int map[] = {2,1,0,3}; float fill[] = {0,0,0,255}; ImageBufAlgo::channels(fixBuf, *imageBuf, roi.chend, map, fill); imageBuf->copy(fixBuf); fixBuf.clear(); } // Fix dimensions if( imageSpec.width != roi.xend || imageSpec.height != roi.yend ) { printf( "\tWARNING: %s is (%i,%i), wanted (%i, %i), Resampling.\n", minimapFile.c_str(), imageSpec.width, imageSpec.height, roi.xend, roi.yend ); ImageBufAlgo::resample(fixBuf, *imageBuf, true, roi); imageBuf->copy(fixBuf); fixBuf.clear(); } pixels = (unsigned char *)imageBuf->localpixels(); // setup DXT1 Compression nvtt::InputOptions inputOptions; inputOptions.setTextureLayout( nvtt::TextureType_2D, 1024, 1024 ); inputOptions.setMipmapData( pixels, 1024, 1024 ); nvtt::CompressionOptions compressionOptions; compressionOptions.setFormat( nvtt::Format_DXT1 ); if( slowcomp ) compressionOptions.setQuality( nvtt::Quality_Normal ); else compressionOptions.setQuality( nvtt::Quality_Fastest ); nvtt::OutputOptions outputOptions; outputOptions.setOutputHeader( false ); NVTTOutputHandler *outputHandler = new NVTTOutputHandler(MINIMAP_SIZE + 1); outputOptions.setOutputHandler( outputHandler ); nvtt::Compressor compressor; compressor.process( inputOptions, compressionOptions, outputOptions ); // Write data to smf smf.write( outputHandler->buffer, MINIMAP_SIZE ); delete outputHandler; smf.close(); delete imageBuf; return false; }
bool SMF::saveHeight() { if( verbose )cout << "INFO: saveHeight\n"; // Dimensions of displacement map. ImageBuf *imageBuf = NULL; ROI roi( 0, width * 64 + 1, // xbegin, xend 0, length * 64 + 1, // ybegin, yend 0, 1, // zbegin, zend 0, 1); // chbegin, chend ImageSpec imageSpec( roi.xend, roi.yend, roi.chend, TypeDesc::UINT16 ); if( is_smf(heightFile) ) { // Load from SMF SMF sourcesmf(heightFile); imageBuf = sourcesmf.getHeight(); } if( !imageBuf ) { // load image file imageBuf = new ImageBuf( heightFile ); imageBuf->read( 0, 0, false, TypeDesc::UINT16 ); if( !imageBuf->initialized() ) { delete imageBuf; imageBuf = NULL; } } if( !imageBuf ) { // Generate blank imageBuf = new ImageBuf( "height", imageSpec ); } imageSpec = imageBuf->specmod(); ImageBuf fixBuf; // Fix the number of channels if( imageSpec.nchannels != roi.chend ) { int map[] = {0}; ImageBufAlgo::channels(fixBuf, *imageBuf, roi.chend, map); imageBuf->copy(fixBuf); fixBuf.clear(); } // Fix the size if ( imageSpec.width != roi.xend || imageSpec.height != roi.yend ) { if( verbose ) printf( "\tWARNING: %s is (%i,%i), wanted (%i, %i), Resampling.\n", heightFile.c_str(), imageSpec.width, imageSpec.height, roi.xend, roi.yend ); ImageBufAlgo::resample(fixBuf, *imageBuf, true, roi); imageBuf->copy(fixBuf); fixBuf.clear(); } // Invert height if ( invert ) { ImageSpec fixSpec(roi.xend, roi.yend, roi.chend, TypeDesc::UINT16); fixBuf.reset( "fixBuf", fixSpec ); const float fill[] = {65535}; ImageBufAlgo::fill(fixBuf, fill); ImageBufAlgo::sub(*imageBuf, fixBuf, *imageBuf); fixBuf.clear(); } // FIXME filter to remove stepping artifacts from 8bit images, // if ( lowpass ) { // } unsigned short *pixels = (unsigned short *)imageBuf->localpixels(); // write height data to smf. char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); fstream smf(filename, ios::binary | ios::in| ios::out); smf.seekp(heightPtr); smf.write( (char *)pixels, imageBuf->spec().image_bytes() ); smf.close(); delete imageBuf; if( is_smf( heightFile ) ) delete [] pixels; return false; }
bool SMF::saveMetal() { if( verbose )cout << "INFO: saveMetal\n"; // Dimensions of displacement map. ImageBuf *imageBuf = NULL; ROI roi( 0, width * 32, // xbegin, xend 0, length * 32, // ybegin, yend 0, 1, // zbegin, zend 0, 1); // chbegin, chend ImageSpec imageSpec( roi.xend, roi.yend, roi.chend, TypeDesc::UINT8 ); if( is_smf(metalFile) ) { // Load from smf SMF sourcesmf(metalFile); imageBuf = sourcesmf.getMetal(); } if( !imageBuf ) { //load from image imageBuf = new ImageBuf(metalFile); imageBuf->read( 0, 0, false, TypeDesc::UINT8 ); if( !imageBuf->initialized() ) { delete imageBuf; imageBuf = NULL; } } if( !imageBuf ) { // Generate blank imageBuf = new ImageBuf( "metal", imageSpec ); } imageSpec = imageBuf->specmod(); ImageBuf fixBuf; // Fix the number of channels if( imageSpec.nchannels != roi.chend ) { int map[] = {0}; ImageBufAlgo::channels(fixBuf, *imageBuf, roi.chend, map); imageBuf->copy(fixBuf); fixBuf.clear(); } // Fix the size if ( imageSpec.width != roi.xend || imageSpec.height != roi.yend ) { if( verbose ) printf( "\tWARNING: %s is (%i,%i), wanted (%i, %i), Resampling.\n", metalFile.c_str(), imageSpec.width, imageSpec.height, roi.xend, roi.yend ); ImageBufAlgo::resample(fixBuf, *imageBuf, true, roi); imageBuf->copy(fixBuf); fixBuf.clear(); } unsigned char *pixels = (unsigned char *)imageBuf->localpixels(); char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); fstream smf(filename, ios::binary | ios::in | ios::out); smf.seekp(metalPtr); // write the data to the smf smf.write( (char *)pixels, imageBuf->spec().image_bytes() ); smf.close(); delete imageBuf; if( is_smf( metalFile ) ) delete [] pixels; return false; }
bool SMF::saveTilemap() { if( verbose )cout << "INFO: saveTilemap\n"; char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); fstream smf(filename, ios::binary | ios::in | ios::out); smf.seekp(tilesPtr); // Tiles Header int nTileFiles = smtList.size(); smf.write( (char *)&nTileFiles, 4); smf.write( (char *)&nTiles, 4); if(verbose)printf( " %i tiles referenced in %i files\n", nTiles, nTileFiles ); // SMT Names for(unsigned int i = 0; i < smtList.size(); ++i) { if( verbose )printf( "\t%i %s\n", smtTiles[i], smtList[i].c_str() ); smf.write( (char *)&smtTiles[i], 4); smf.write( smtList[i].c_str(), smtList[i].size() +1 ); } // Dimensions of displacement map. ImageBuf *imageBuf = NULL; ROI roi( 0, width * 16, // xbegin, xend 0, length * 16, // ybegin, yend 0, 1, // zbegin, zend 0, 1); // chbegin, chend ImageSpec imageSpec( roi.xend, roi.yend, roi.chend, TypeDesc::UINT ); if( is_smf(tilemapFile) ) { // Load from SMF SMF sourcesmf(tilemapFile); imageBuf = sourcesmf.getTilemap(); } if( !imageBuf ) { // load image file imageBuf = new ImageBuf( tilemapFile ); imageBuf->read( 0, 0, false, TypeDesc::UINT ); if( !imageBuf->initialized() ) { delete imageBuf; imageBuf = NULL; } } if( !imageBuf ) { // Generate blank imageBuf = new ImageBuf( "tilemap", imageSpec ); for ( unsigned int i = 0; i < imageSpec.image_pixels(); ++i ) ((unsigned int *)imageBuf->localpixels())[ i ] = i; } imageSpec = imageBuf->specmod(); ImageBuf fixBuf; // Fix the number of channels if( imageSpec.nchannels != roi.chend ) { int map[] = {0}; ImageBufAlgo::channels(fixBuf, *imageBuf, roi.chend, map); imageBuf->copy(fixBuf); fixBuf.clear(); } // Fix the size // FIXME image should never be resized, instead tiling either from an edge or centred. if ( imageSpec.width != roi.xend || imageSpec.height != roi.yend ) { if( verbose ) printf( "\tWARNING: %s is (%i,%i), wanted (%i, %i), Resampling.\n", tilemapFile.c_str(), imageSpec.width, imageSpec.height, roi.xend, roi.yend ); ImageBufAlgo::resample(fixBuf, *imageBuf, false, roi); imageBuf->copy(fixBuf); fixBuf.clear(); } unsigned int *pixels = (unsigned int *)imageBuf->localpixels(); // write the data to the smf smf.write( (char *)pixels, imageBuf->spec().image_bytes() ); smf.close(); delete imageBuf; if( is_smf( tilemapFile ) ) delete [] pixels; return false; }
/** In- and output of an unstructured mesh. * This function demonstrates * - how to define and create a mesh * - read a mesh from a file (base::io::smf) * - extract the boundary from the mesh * - write output in vtk and SMF format * * The image shows the reference meshes in this application * \image html simplexMeshes.png "Triangle (left) and tetrahedron mesh (right)" * and the boundary meshes are given in the next picture * \image html boundaryMeshes.png "Line (left) and triangle mesh(right)" * * \param[in] argc Number of command line arguments * \param[in] argv Values of command line arguments */ int ref01::unstructured( int argc, char* argv[] ) { //-------------------------------------------------------------------------- // Definition of the spatial dimension const unsigned dim = SPACEDIM; // Defintion of an element shape const base::Shape elemShape = base::SimplexShape<dim>::value; // Definition of the polynomial degree of the geometry approximation const unsigned geomDeg = 1; // Check the number of input arguments if ( argc != 2 ) { // note argv[0] is the program name itself usageMessage1<elemShape,geomDeg>( argv[0] ); return 0; } // convert input argument to a string object const std::string smfFileName = boost::lexical_cast<std::string>( argv[1] ); // extract the basename of the file const std::string baseName = base::io::baseName( smfFileName, ".smf" ); typedef base::Unstructured<elemShape,geomDeg> Mesh; // Create an empty mesh object Mesh mesh; //-------------------------------------------------------------------------- { // input file stream from smf file std::ifstream smf( smfFileName.c_str() ); // read smf mesh base::io::smf::readMesh( smf, mesh ); // close the stream smf.close(); } //-------------------------------------------------------------------------- typedef base::mesh::BoundaryMeshBinder<Mesh::Element>::Type BoundaryMesh; BoundaryMesh boundaryMesh; { // Create list of <Element,faceNo> pairs base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); // Create a real mesh object from this list base::mesh::generateBoundaryMesh( meshBoundary.begin(), meshBoundary.end(), mesh, boundaryMesh ); } //-------------------------------------------------------------------------- // Output functions { // VTK file of the input mesh { // file name for vtk mesh file const std::string vtkMeshFileName = baseName + ".vtk"; // output file stream std::ofstream vtk( vtkMeshFileName.c_str() ); // create a VTK writer base::io::vtk::LegacyWriter vtkWriter( vtk ); // write the mesh vtkWriter.writeUnstructuredGrid( mesh ); // close the stream vtk.close(); } // SMF file of the boundary mesh { // file name for boundary mesh output const std::string smfBoundaryFileName = baseName + "_boundary.smf"; // output stream std::ofstream smf( smfBoundaryFileName.c_str() ); // write to smf base::io::smf::writeMesh( boundaryMesh, smf ); // close stream smf.close(); } } return 0; }
bool SMF::load(string filename) { bool ret = false; char magic[16]; // Perform tests for file validity ifstream smf(filename.c_str(), ifstream::in); if( !smf.good() ) { if ( !quiet )printf( "ERROR: Cannot open %s\n", filename.c_str() ); ret = true; } smf.read( magic, 16); // perform test for file format if( strcmp(magic, "spring map file") ) { if( !quiet )printf("ERROR: %s is not a valid smf file.\n", filename.c_str() ); ret = true; } if( ret ) return ret; heightFile = typeFile = minimapFile = metalFile = grassFile = tilemapFile = featuresFile = filename; loadFile = filename; smf.seekg(0); smf.read( (char *)&header, sizeof(SMFHeader) ); // convert internal units to spring map units. width = header.width / 64; length = header.length / 64; floor = (float)header.floor / 512; ceiling = (float)header.ceiling / 512; heightPtr = header.heightPtr; typePtr = header.typePtr; tilesPtr = header.tilesPtr; minimapPtr = header.minimapPtr; metalPtr = header.metalPtr; featuresPtr = header.featuresPtr; if( verbose ) { printf("INFO: Loading %s\n", filename.c_str() ); printf("\tVersion: %i\n", header.version ); printf("\tID: %i\n", header.id ); printf("\tWidth: %i\n", width ); printf("\tLength: %i\n", length ); printf("\tSquareSize: %i\n", header.squareWidth ); printf("\tTexelPerSquare: %i\n", header.squareTexels ); printf("\tTileSize: %i\n", header.tileTexels ); printf("\tMinHeight: %f\n", floor ); printf("\tMaxHeight: %f\n", ceiling ); printf("\tHeightMapPtr: %i\n", heightPtr ); printf("\tTypeMapPtr: %i\n", typePtr ); printf("\tTilesPtr: %i\n", tilesPtr ); printf("\tMiniMapPtr: %i\n", minimapPtr ); printf("\tMetalMapPtr: %i\n", metalPtr ); printf("\tFeaturePtr: %i\n", featuresPtr ); printf("\tExtraHeaders: %i\n", header.nExtraHeaders ); } //fi verbose // Extra headers Information int offset; SMFEH extraHeader; for(int i = 0; i < header.nExtraHeaders; ++i ) { if( verbose )cout << " Extra Headers" << endl; offset = smf.tellg(); smf.read( (char *)&extraHeader, sizeof(SMFEH) ); smf.seekg(offset); if(extraHeader.type == 0) { if( verbose )printf("\tNUll type: 0\n"); continue; } if(extraHeader.type == 1) { SMFEHGrass *grassHeader = new SMFEHGrass; smf.read( (char *)grassHeader, sizeof(SMFEHGrass)); if( verbose )printf("\tGrass: Size %i, type %i, Ptr %i\n", grassHeader->size, grassHeader->type, grassHeader->grassPtr); extraHeaders.push_back( (SMFEH *)grassHeader ); } else { ret = true; if( verbose )printf("WARNING: %i is an unknown header type\n", i); } smf.seekg( offset + extraHeader.size); } // Tileindex Information SMFHTiles tilesHeader; smf.seekg( header.tilesPtr ); smf.read( (char *)&tilesHeader, sizeof( SMFHTiles ) ); nTiles = tilesHeader.nTiles; if( verbose )printf(" %i tiles referenced in %i files.\n", tilesHeader.nTiles, tilesHeader.nFiles); char temp_fn[256]; int nTiles; for ( int i=0; i < tilesHeader.nFiles; ++i) { smf.read( (char *)&nTiles, 4); smtTiles.push_back(nTiles); smf.getline( temp_fn, 255, '\0' ); if( verbose )printf( "\t%i %s\n", nTiles, temp_fn ); smtList.push_back(temp_fn); } // Featurelist information smf.seekg( header.featuresPtr ); int nTypes; smf.read( (char *)&nTypes, 4); int nFeatures; smf.read( (char *)&nFeatures, 4); if( verbose )printf(" Features: %i, Feature types: %i\n", nFeatures, nTypes); offset = smf.tellg(); smf.seekg (0, ios::end); int filesize = smf.tellg(); smf.seekg(offset); int eeof = offset + nFeatures * sizeof(SMFFeature); if( eeof > filesize ) { if( !quiet )printf( "WARNING: Filesize is not large enough to contain the reported number of features. Ignoring feature data.\n"); nFeatures = 0; nTypes = 0; } char temp[256]; for ( int i = 0; i < nTypes; ++i ) { smf.getline(temp, 255, '\0' ); featureTypes.push_back(temp); } SMFFeature feature; for ( int i = 0; i < nFeatures; ++i ) { smf.read( (char *)&feature, sizeof(SMFFeature) ); features.push_back(feature); } smf.close(); recalculate(); return false; }
/** Solve a mixed boundary value problem based on Poisson's equation * * New features are * - application of Neumann boundary conditions and body forces * - use classes to describe the reference solution and the boundary * value problem * - convergence analysis (if executed for many meshes) * * The picture shows the convergence behaviour of the method * for various mesh sizes, a linear finite element basis * \code{.cpp} * const unsigned fieldDeg = 1; * \endcode * and a quadratic finite element basis * \code{.cpp} * const unsigned fieldDeg = 2; * \endcode * in the \f$ L_2 \f$-norm * \f[ * \| u - u^h \|_{L_2(\Omega)}^2 * = \int_\Omega (u - u^h)^2 d x * \f] * and the \f$ H^1 \f$-semi-norm * \f[ * | u - u^h |_{H^1(\Omega)}^2 * = \int_\Omega (\nabla u - \nabla u^h)^2 d x * \f] * * \image html convergence.png "Convergence diagram" * */ int ref05::mixedPoisson( int argc, char * argv[] ) { if ( argc != 2 ) { std::cout << "Usage: " << argv[0] << " file.smf \n\n"; return -1; } const std::string smfFile = boost::lexical_cast<std::string>( argv[1] ); const std::string baseName = base::io::baseName( smfFile, ".smf" ); //-------------------------------------------------------------------------- const unsigned geomDeg = 1; const unsigned fieldDeg = 2; const base::Shape shape = base::QUAD; const unsigned doFSize = 1; //-------------------------------------------------------------------------- typedef base::Unstructured<shape,geomDeg> Mesh; const unsigned dim = Mesh::Node::dim; Mesh mesh; { std::ifstream smf( smfFile.c_str() ); base::io::smf::readMesh( smf, mesh ); smf.close(); } // Quadrature and surface quadrature const unsigned kernelDegEstimate = 3; typedef base::Quadrature<kernelDegEstimate,shape> Quadrature; Quadrature quadrature; typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature; SurfaceQuadrature surfaceQuadrature; // DOF handling 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 ); // Object of reference solution and the Poisson problem typedef ReferenceSolution<dim> RefSol; typedef GivenData<RefSol> GivenData; RefSol refSol( 3., 5., 4. ); GivenData givenData( refSol ); // Creates a list of <Element,faceNo> pairs base::mesh::MeshBoundary meshBoundary; meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() ); // Object to constrain the boundary base::dof::constrainBoundary<FEBasis>( meshBoundary.begin(), meshBoundary.end(), mesh, field, boost::bind( &GivenData::dirichletBC<DoF>, &givenData, _1, _2 ) ); // Number of DoFs after constraint application! const std::size_t numDofs = base::dof::numberDoFsConsecutively( field.doFsBegin(), field.doFsEnd() ); std::cout << "Number of dofs " << numDofs << std::endl; // Create a solver object typedef base::solver::Eigen3 Solver; Solver solver( numDofs ); // Bind the fields together typedef base::asmb::FieldBinder<Mesh,Field> FieldBinder; FieldBinder fieldBinder( mesh, field ); typedef FieldBinder::TupleBinder<1,1>::Type FTB; // Body force base::asmb::bodyForceComputation<FTB>( quadrature, solver, fieldBinder, boost::bind( &GivenData::forceFun, &givenData, _1 ) ); #if 0 base::asmb::bodyForceComputation2<FTB>( quadrature, solver, fieldBinder, boost::bind( &GivenData::forceFun2<Mesh::Element>, &givenData, _1, _2 ) ); #endif // Create a connectivity out of 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 ); } typedef base::asmb::SurfaceFieldBinder<BoundaryMesh,Field> SurfaceFieldBinder; SurfaceFieldBinder surfaceFieldBinder( boundaryMesh, field ); typedef SurfaceFieldBinder::TupleBinder<1>::Type SFTB; // Neumann boundary condition base::asmb::neumannForceComputation<SFTB>( surfaceQuadrature, solver, surfaceFieldBinder, boost::bind( &GivenData::neumannBC, &givenData, _1, _2 ) ); // compute stiffness matrix typedef heat::Laplace<FTB::Tuple> Laplace; Laplace laplace( 1. ); base::asmb::stiffnessMatrixComputation<FTB>( quadrature, solver, fieldBinder, laplace ); // Finalise assembly solver.finishAssembly(); // Solve solver.choleskySolve(); // distribute results back to dofs base::dof::setDoFsFromSolver( solver, field ); //-------------------------------------------------------------------------- // output to a VTK file { // VTK Legacy const std::string vtkFile = baseName + ".vtk"; std::ofstream vtk( vtkFile.c_str() ); base::io::vtk::LegacyWriter vtkWriter( vtk ); vtkWriter.writeUnstructuredGrid( mesh ); base::io::vtk::writePointData( vtkWriter, mesh, field, "temperature" ); const base::Vector<dim>::Type xi = base::ShapeCentroid<Mesh::Element::shape>::apply(); base::io::vtk::writeCellData( vtkWriter, mesh, field, boost::bind( base::post::evaluateFieldGradient< Mesh::Element, Field::Element>, _1, _2, xi ), "flux" ); vtk.close(); } //-------------------------------------------------------------------------- // compute L2-error std::cout << "L2-error = " << base::post::errorComputation<0>( quadrature, mesh, field, boost::bind( &ReferenceSolution<dim>::evaluate, &refSol, _1 ) ) << '\n'; //-------------------------------------------------------------------------- // compute H1-error std::cout << "H1-error = " << base::post::errorComputation<1>( quadrature, mesh, field, boost::bind( &ReferenceSolution<dim>::evaluateGradient, &refSol, _1 ) ) << '\n'; //-------------------------------------------------------------------------- // Compute mesh volume double volume = 0.; base::asmb::simplyIntegrate<FTB>( quadrature, volume, fieldBinder, base::kernel::Measure<FTB::Tuple>() ); std::cout << "Volume of mesh: " << volume << '\n'; return 0; }
bool SMF::saveGrass() { if( verbose )cout << "INFO: saveGrass\n"; SMFEHGrass *grassHeader = NULL; for( unsigned int i = 0; i < extraHeaders.size(); ++i ) { if( extraHeaders[ i ]->type == 1 ) grassHeader = reinterpret_cast<SMFEHGrass *>( extraHeaders[ i ] ); } if( !grassHeader )return true; ImageBuf *imageBuf = NULL; ROI roi( 0, width * 16, 0, length * 16, 0, 1, 0, 1); ImageSpec imageSpec(roi.xend, roi.yend, roi.chend, TypeDesc::UINT8 ); if( is_smf(grassFile) ) { // Load from SMF SMF sourcesmf(grassFile); imageBuf = sourcesmf.getGrass(); } if( !imageBuf ) { // Load image file imageBuf = new ImageBuf( grassFile ); imageBuf->read( 0, 0, false, TypeDesc::UINT8 ); if( imageBuf->initialized() ) { delete imageBuf; imageBuf = NULL; } } if( !imageBuf ) { // Generate blank imageBuf = new ImageBuf( "grass", imageSpec ); } imageSpec = imageBuf->specmod(); ImageBuf fixBuf; // Fix the number of channels if( imageSpec.nchannels != roi.chend ) { int map[] = {0}; ImageBufAlgo::channels(fixBuf, *imageBuf, roi.chend, map ); imageBuf->copy( fixBuf ); fixBuf.clear(); } // Fix the Dimensions if ( imageSpec.width != roi.xend || imageSpec.height != roi.yend ) { if( verbose ) printf( "\tWARNING: %s is (%i,%i), wanted (%i, %i) Resampling.\n", typeFile.c_str(), imageSpec.width, imageSpec.height, roi.xend, roi.yend); ImageBufAlgo::resample(fixBuf, *imageBuf, false, roi); imageBuf->copy( fixBuf ); fixBuf.clear(); } unsigned char *pixels = (unsigned char *)imageBuf->localpixels(); char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); if( verbose )printf( " Source: %s.\n", grassFile.c_str() ); fstream smf(filename, ios::binary | ios::in | ios::out); smf.seekp(grassHeader->grassPtr); smf.write( (char *)pixels, imageBuf->spec().image_bytes() ); smf.close(); delete imageBuf; if( is_smf( grassFile ) ) delete [] pixels; return false; }
//------------------------------------------------------------------------------ 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; }
//------------------------------------------------------------------------------ int main( int argc, char * argv[] ) { base::auxi::Timer total, detailed; //-------------------------------------------------------------------------- // User input if ( argc != 5 ) { std::cout << "Usage: " << argv[0] << " file.smf radius E1 E2 \n\n"; return -1; } // input mesh file const std::string smfFile = boost::lexical_cast<std::string>( argv[1] ); const std::string baseName = base::io::baseName( smfFile, ".smf" ); // problem parameter const double radius = boost::lexical_cast<double>( argv[2] ); const double E1 = boost::lexical_cast<double>( argv[3] ); const double E2 = boost::lexical_cast<double>( argv[4] ); const double penaltyFactor = 20.0; // material stuff const double nu = 0.3; const double lambda1 = mat::Lame::lambda( E1, nu ); const double lambda2 = mat::Lame::lambda( E2, nu ); const double mu1 = mat::Lame::mu( E1, nu ); const double mu2 = mat::Lame::mu( E2, nu ); //-------------------------------------------------------------------------- const unsigned geomDeg = 1; const unsigned dim = SPACEDIM; const base::Shape shape = base::SimplexShape<dim>::value; const bool isSigned = true; const unsigned fieldDeg = 1; const unsigned doFSize = dim; // use Nitsche const bool useNitscheTerms = true; //-------------------------------------------------------------------------- // Domain mesh typedef base::Unstructured<shape,geomDeg> Mesh; Mesh mesh; { std::ifstream smf( smfFile.c_str() ); base::io::smf::readMesh( smf, mesh ); } //-------------------------------------------------------------------------- // Compute the level set data typedef base::cut::LevelSet<dim> LevelSet; std::vector<LevelSet> levelSet; base::cut::AnalyticSurface<dim>::Type as = boost::bind( &interface<dim>, _1, radius, _2 ); base::cut::analyticLevelSet( mesh, as, isSigned, levelSet ); //-------------------------------------------------------------------------- // FE typedef base::fe::Basis<shape,fieldDeg> FEBasis; typedef base::cut::ScaledField<FEBasis,doFSize> Field; Field fieldIn, fieldOut; base::dof::generate<FEBasis>( mesh, fieldIn ); base::dof::generate<FEBasis>( mesh, fieldOut ); //-------------------------------------------------------------------------- // Cut typedef base::cut::Cell<shape> Cell; std::vector<Cell> cells; base::cut::generateCutCells( mesh, levelSet, cells ); //-------------------------------------------------------------------------- // surface meshes typedef base::cut::SurfaceMeshBinder<Mesh>::SurfaceMesh SurfaceMesh; SurfaceMesh boundaryMesh, interfaceMesh; // 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( &dirichletBoundary<dim>, _1 ) ); } // from interface base::cut::generateSurfaceMesh<Mesh,Cell>( mesh, cells, interfaceMesh ); //-------------------------------------------------------------------------- // Quadratures const unsigned kernelDegEstimate = 5; // for domain typedef base::cut::Quadrature<kernelDegEstimate,shape> CutQuadrature; CutQuadrature cutQuadratureIn( cells, true ); CutQuadrature cutQuadratureOut( cells, false ); // for surface typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature; SurfaceQuadrature surfaceQuadrature; //-------------------------------------------------------------------------- // Bind fields // for domain fields typedef base::asmb::FieldBinder<Mesh,Field,Field> FieldBinder; typedef FieldBinder::TupleBinder<1,1>::Type FTB1; typedef FieldBinder::TupleBinder<2,2>::Type FTB2; FieldBinder fieldBinder( mesh, fieldIn, fieldOut ); // for surface fields typedef base::asmb::SurfaceFieldBinder<SurfaceMesh,Field,Field> SurfaceFieldBinder; typedef SurfaceFieldBinder::TupleBinder<1,1>::Type STB11; typedef SurfaceFieldBinder::TupleBinder<2,2>::Type STB22; typedef SurfaceFieldBinder::TupleBinder<1,2>::Type STB12; typedef SurfaceFieldBinder::TupleBinder<2,1>::Type STB21; SurfaceFieldBinder boundaryFieldBinder( boundaryMesh, fieldIn, fieldOut ); SurfaceFieldBinder interfaceFieldBinder( interfaceMesh, fieldIn, fieldOut ); // compute supports, scale basis const std::size_t numDoFs = std::distance( fieldIn.doFsBegin(), fieldIn.doFsEnd() ); std::vector<double> supportsIn, supportsOut; supportsIn.resize( numDoFs ); supportsOut.resize( numDoFs ); base::cut::supportComputation( mesh, fieldIn, cutQuadratureIn, supportsIn ); base::cut::supportComputation( mesh, fieldOut, cutQuadratureOut, supportsOut ); fieldIn.scaleAndTagBasis( supportsIn, 1.e-10 ); fieldOut.scaleAndTagBasis( supportsOut, 1.e-10 ); //fieldIn.tagBasis( supportsIn, 1.e-10 ); //fieldOut.tagBasis( supportsOut, 1.e-10 ); // number DoFs, create solver const std::size_t activeDoFsIn = base::dof::numberDoFsConsecutively( fieldIn.doFsBegin(), fieldIn.doFsEnd() ); const std::size_t activeDoFsOut = base::dof::numberDoFsConsecutively( fieldOut.doFsBegin(), fieldOut.doFsEnd(), activeDoFsIn ); typedef base::solver::Eigen3 Solver; Solver solver( activeDoFsIn + activeDoFsOut ); message( "Preprocessing time = " + detailed.print() ); detailed.reset(); //-------------------------------------------------------------------------- // Stiffness matrix typedef mat::hypel::StVenant Material; Material material1( lambda1, mu1 ); Material material2( lambda2, mu2 ); // matrix kernel typedef solid::HyperElastic<Material,FTB1::Tuple> HyperElastic1; HyperElastic1 hyperElastic1( material1 ); typedef solid::HyperElastic<Material,FTB2::Tuple> HyperElastic2; HyperElastic2 hyperElastic2( material2 ); message( "Stiffness" ); base::asmb::stiffnessMatrixComputation<FTB1>( cutQuadratureIn, solver, fieldBinder, hyperElastic1 ); base::asmb::stiffnessMatrixComputation<FTB2>( cutQuadratureOut, solver, fieldBinder, hyperElastic2 ); // boundary conditions #if 1 { message("Boundary Penalty"); base::nitsche::OuterBoundary ob1( E1); base::nitsche::OuterBoundary ob2( E2); base::nitsche::penaltyLHS<STB11>( surfaceQuadrature, solver, boundaryFieldBinder, ob1, penaltyFactor ); base::nitsche::penaltyLHS<STB22>( surfaceQuadrature, solver, boundaryFieldBinder, ob2, penaltyFactor ); base::nitsche::penaltyRHS<STB11>( surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1), ob1, penaltyFactor ); base::nitsche::penaltyRHS<STB22>( surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1), ob2, penaltyFactor ); if ( useNitscheTerms ) { message("Boundary Nitsche"); base::nitsche::energyLHS<STB11>( hyperElastic1, surfaceQuadrature, solver, boundaryFieldBinder, ob1 ); base::nitsche::energyLHS<STB22>( hyperElastic2, surfaceQuadrature, solver, boundaryFieldBinder, ob2 ); base::nitsche::energyRHS<STB11>( hyperElastic1, surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1), ob1 ); base::nitsche::energyRHS<STB22>( hyperElastic2, surfaceQuadrature, solver, boundaryFieldBinder, boost::bind( &dirichlet<dim>, _1), ob2 ); } } // interface conditions { message("Interface Penalty"); base::nitsche::ImmersedInterface<Cell> ip( E1, E2, cells ); base::nitsche::penaltyLHS<STB11>( surfaceQuadrature, solver, interfaceFieldBinder, ip, penaltyFactor ); base::nitsche::penaltyLHS<STB22>( surfaceQuadrature, solver, interfaceFieldBinder, ip, penaltyFactor ); base::nitsche::penaltyLHS<STB12>( surfaceQuadrature, solver, interfaceFieldBinder, ip, -penaltyFactor ); base::nitsche::penaltyLHS<STB21>( surfaceQuadrature, solver, interfaceFieldBinder, ip, -penaltyFactor ); if ( useNitscheTerms ) { message("Interface Nitsche"); base::nitsche::energyLHS<STB11>( hyperElastic1, surfaceQuadrature, solver, interfaceFieldBinder, ip, true, true ); // kappa1 base::nitsche::energyLHS<STB21>( hyperElastic1, surfaceQuadrature, solver, interfaceFieldBinder, ip, true, false ); // -kappa1 base::nitsche::energyLHS<STB12>( hyperElastic2, surfaceQuadrature, solver, interfaceFieldBinder, ip, false, true ); // kappa2 base::nitsche::energyLHS<STB22>( hyperElastic2, surfaceQuadrature, solver, interfaceFieldBinder, ip, false, false ); // -kappa2 } } #endif //-------------------------------------------------------------------------- // Solve and distribute solver.finishAssembly(); message( "Assembly time = " + detailed.print() ); detailed.reset(); #ifdef VERBOSE { solver.systemInfo( std::cout ); std::ofstream mat( "matrix" ); solver.debugLHS( mat ); std::ofstream vec( "vector" ); solver.debugRHS( vec ); } #endif #if 1 // decide to solve and post-process //solver.choleskySolve(); const unsigned numCGIter = solver.cgSolve(); //message( "Solve time = " + detailed.print() ); const double solveTime = detailed.seconds(); detailed.reset(); base::dof::setDoFsFromSolver( solver, fieldIn ); base::dof::setDoFsFromSolver( solver, fieldOut ); //-------------------------------------------------------------------------- // Extract distances, closestPoints and location flags from level set data { } //-------------------------------------------------------------------------- { const std::string vtkFile = baseName + ".vtk"; std::ofstream vtk( vtkFile.c_str() ); base::io::vtk::LegacyWriter vtkWriter( vtk ); vtkWriter.writeUnstructuredGrid( mesh ); { std::vector<double> distances; std::transform( levelSet.begin(), levelSet.end(), std::back_inserter( distances ), boost::bind( &LevelSet::getSignedDistance, _1 ) ); vtkWriter.writePointData( distances.begin(), distances.end(), "distances" ); } { std::vector<bool> location; std::transform( levelSet.begin(), levelSet.end(), std::back_inserter( location ), boost::bind( &LevelSet::isInterior, _1 ) ); vtkWriter.writePointData( location.begin(), location.end(), "location" ); } vtkWriter.writePointData( supportsIn.begin(), supportsIn.end(), "suppIn" ); vtkWriter.writePointData( supportsOut.begin(), supportsOut.end(), "suppOut" ); base::io::vtk::writePointData( vtkWriter, mesh, fieldIn, "fieldIn" ); base::io::vtk::writePointData( vtkWriter, mesh, fieldOut, "fieldOut" ); vtk.close(); } #ifdef VERBOSE // decide error verbosity // integrate double volumeIn = 0.; base::asmb::simplyIntegrate<FTB1>( cutQuadratureIn, volumeIn, fieldBinder, base::kernel::Measure<FTB1::Tuple>() ); double volumeOut = 0.; base::asmb::simplyIntegrate<FTB2>( cutQuadratureOut, volumeOut, fieldBinder, base::kernel::Measure<FTB2::Tuple>() ); std::cout << "Volume of mesh: " << volumeIn << " + " << volumeOut << " = " << volumeIn + volumeOut << '\n'; #else // for convergence analysis std::cout << solveTime << " " << numCGIter << "\n"; #endif #endif // decide to solve and write message( "Post-process time = " + detailed.print() ); message( "---------------------------------------" ); message( "Total time = " + total.print() ); return 0; }
/** 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; }
bool SMF::save() { char filename[256]; sprintf( filename, "%s.smf", outPrefix.c_str() ); ofstream smf(filename, ios::binary | ios::out); if( verbose )printf( "\nINFO: Saving %s.\n", filename ); char magic[] = "spring map file\0"; smf.write( magic, 16 ); int version = 1; smf.write( (char *)&version, 4); if( verbose )printf( "\tVersion: %i.\n", version ); int id = rand(); smf.write( (char *)&id, 4); if( verbose )printf( "\tMapID: %i.\n", id ); int width = this->width * 64; smf.write( (char *)&width, 4); if( verbose )printf( "\tWidth: %i.\n", width ); int length = this->length * 64; smf.write( (char *)&length, 4); if( verbose )printf( "\tLength: %i.\n", length ); int squareWidth = 8; smf.write( (char *)&squareWidth, 4); if( verbose )printf( "\tSquareWidth: %i.\n", squareWidth ); int squareTexels = 8; smf.write( (char *)&squareTexels, 4); if( verbose )printf( "\tSquareTexels: %i.\n", squareTexels ); int tileTexels = 32; smf.write( (char *)&tileTexels, 4); if( verbose )printf( "\tTileTexels: %i.\n", tileTexels ); float floor = this->floor * 512; smf.write( (char *)&floor, 4); if( verbose )printf( "\tMinHeight: %0.2f.\n", floor ); float ceiling = this->ceiling * 512; smf.write( (char *)&ceiling, 4); if( verbose )printf( "\tMaxHeight: %0.2f.\n", ceiling ); smf.write( (char *)&heightPtr, 4); if( verbose )printf( "\tHeightPtr: %i.\n", heightPtr ); smf.write( (char *)&typePtr, 4); if( verbose )printf( "\tTypePtr: %i.\n", typePtr ); smf.write( (char *)&tilesPtr, 4); if( verbose )printf( "\tTilesPtr: %i.\n", tilesPtr ); smf.write( (char *)&minimapPtr, 4); if( verbose )printf( "\tMinimapPtr: %i.\n", minimapPtr ); smf.write( (char *)&metalPtr, 4); if( verbose )printf( "\tMetalPtr: %i.\n", metalPtr ); smf.write( (char *)&featuresPtr, 4); if( verbose )printf( "\tFeaturesPtr: %i.\n", featuresPtr ); int nExtraHeaders = extraHeaders.size(); smf.write( (char *)&nExtraHeaders, 4); if( verbose )printf( "\tExtraHeaders: %i.\n", nExtraHeaders ); if(verbose) printf( " Extra Headers:\n"); for( unsigned int i = 0; i < extraHeaders.size(); ++i ) { smf.write((char *)extraHeaders[i], extraHeaders[i]->size); if( verbose ) { if(extraHeaders[i]->type == 1) printf("\tGrassPtr: %i.\n", ((SMFEHGrass *)extraHeaders[i])->grassPtr ); else printf( "\t Unknown Header\n"); } } smf.close(); saveHeight(); saveType(); saveMinimap(); saveMetal(); for( unsigned int i = 0; i < extraHeaders.size(); ++i ) { if(extraHeaders[i]->type == 1)saveGrass(); } saveTilemap(); saveFeatures(); return false; }