/* * File: MaterialModel.cpp * Author: David * * Created on 24. March 2014 */ #include "MaterialModelImpl.h" #include #include using namespace std; #include #include namespace vdb = openvdb::v2_2_0; namespace FractureSim{ MaterialModel* createMaterialModel(string spec, double youngsMod, double poissonsRatio, double density, double strength, double toughness, double compress){ if(spec.compare("?")==0){ // print options printf( "\nthe following material model specifications are implemented:\n" "default ... homogeneous material\n" "'lay(nx,ny,nz,f,p,K)' ... layered material with normal (nx,ny,nz), frequency f, phase p and secondary toughness K\n" "'test' ... dummy material model (used for testing)\n" ); } if(spec.compare(0,3,"lay")==0){ // format: "lay(nx,ny,nz,f,p,Kc_hard)" or "lay(nx,ny,nz,f,p,K_hard/snx,sny,snz,sf,sp,Sc_hard)" double nx,ny,nz,f,p,k; char c; int done = sscanf(spec.substr(3).c_str(), "(%lg,%lg,%lg,%lg,%lg,%lg%c", &nx,&ny,&nz,&f,&p,&k,&c); if(done == 7 && c == ')'){ Eigen::Vector3d n(nx,ny,nz); n.normalize(); return new LayeredMaterialModel( youngsMod, poissonsRatio,density, strength, compress, toughness, k, 2.0*M_PI*f, p, n); }else if(done == 7 && c == '/'){ // also use varying strength double snx,sny,snz,sf,sp,s; int done = sscanf(spec.substr( spec.find_first_of('/') ).c_str(), "/%lg,%lg,%lg,%lg,%lg,%lg%c", &snx,&sny,&snz,&sf,&sp,&s,&c); if(done == 7 && c == ')'){ Eigen::Vector3d n(nx,ny,nz); n.normalize(); Eigen::Vector3d sn(snx,sny,snz); sn.normalize(); return new LayeredMaterialModel( youngsMod, poissonsRatio,density, strength, compress, toughness, k, 2.0*M_PI*f, p, n, s, 2.0*M_PI*sf, sp, sn ); } } } if(spec.compare("tube")==0){ return new TubedMaterialModel(youngsMod, poissonsRatio,density, strength, compress, toughness, 2.0*toughness); } if(spec.compare("test")==0){ return new DummyMaterialModel(youngsMod, poissonsRatio,density, strength,toughness, compress, 3.0); } if(spec.compare(0,3,"vdb")==0){ // format: "vdb(filename/toughnessGridName/strengthGridName,scaleFactor,voxelSize,useUDF)" std::string file, toughname="toughness", strengthname="strength"; file=spec.substr(4, spec.find_first_of(',')-4); //printf("\n1) file=\"%s\"",file.c_str()); if(file.find_first_of('/')!=file.npos){ toughname=file.substr(file.find_first_of('/')+1); //printf("\n2) tough=\"%s\"", toughname.c_str()); file=file.substr(0,file.find_first_of('/')); //printf("\n2) file=\"%s\"",file.c_str()); strengthname=toughname; } if(toughname.find_first_of('/')!=toughname.npos){ strengthname=toughname.substr(toughname.find_first_of('/')+1); //printf("\n3) strength=\"%s\"", strengthname.c_str()); toughname=toughname.substr(0,toughname.find_first_of('/')); //printf("\n3) tough=\"%s\"",toughname.c_str()); } //printf("\n4) remainder = \"%s\"", spec.substr(spec.find_first_of(',')+1).c_str()); double scale, voxelSize; int readUDF; char check=0; sscanf( spec.substr(spec.find_first_of(',')+1).c_str(), "%lf,%lf,%d%c", &scale, &voxelSize, &readUDF, &check); if(check!=')'){ printf("\nillegal definition of VDB material: %s, use " "\"vdb(filename/toughnessGridName/strengthGridName,scaleFactor,voxelSize,useUDF)\"", spec.c_str()); }else{ printf("\n%% ... VDB material model: %s / %s / %s scale %.3lg, voxel size %.3lg, udf %d", file.c_str(), toughname.c_str(), strengthname.c_str(), scale, voxelSize, (readUDF!=0)); return new VDBMaterialModel( youngsMod, poissonsRatio,density, strength,toughness, compress, file,toughname,strengthname,readUDF!=0, scale ,voxelSize); } } printf("\n%% ... using default material model"); return new HomogeneousMaterialModel( youngsMod, poissonsRatio,density, strength,toughness, compress); } // DummyMaterialModel ================================================================================== //// "y-split" - doesn't have a proper gradient, testing how badly this affects results //double DummyMaterialModel::fractureToughness(const Eigen::Vector3d& x) const{ // return Kc* (1.0 + KcDelta* (x[1]>0.0?1.0:0.0)); //} //void DummyMaterialModel::fractureToughnessGradient(Eigen::Vector3d& dKc, const Eigen::Vector3d& x) const{ // dKc.setZero(); double h=1e-2; // dKc[1]=2.0*h*(fractureToughness(x+h*Eigen::Vector3d::UnitY())-fractureToughness(x-h*Eigen::Vector3d::UnitY())); //} // cos-"bubbles" double DummyMaterialModel::fractureToughness(const Eigen::Vector3d& x) const{ const double w=15*M_PI; return Kc* (1.0 + KcDelta* (0.5 + 0.5*cos(w*x[0])*cos(w*x[1])*cos(w*x[2]))); } void DummyMaterialModel::fractureToughnessGradient(Eigen::Vector3d& dKc, const Eigen::Vector3d& x) const{ const double w=15*M_PI; dKc[0]= -Kc*KcDelta* 0.5*w*sin(w*x[0])*cos(w*x[1])*cos(w*x[2]); dKc[1]= -Kc*KcDelta* 0.5*w*cos(w*x[0])*sin(w*x[1])*cos(w*x[2]); dKc[2]= -Kc*KcDelta* 0.5*w*cos(w*x[0])*cos(w*x[1])*sin(w*x[2]); } // ===================================================================================================== // LayeredMaterialModel ================================================================================== double LayeredMaterialModel::tensileStrength(const Eigen::Vector3d& x) const { double w = 0.5 + 0.5*cos(sf * x.dot(sn) + sp); // w is in [0, 1] // printf("\n strength eval at (%+.2lf, %+.2lf, %+.2lf) is %.3lg (w=%.3lf)", // x[0],x[1],x[2] , (1.0-w)*Sc + w*ScHard ,w); return (1.0-w)*Sc + w*ScHard; } double LayeredMaterialModel::fractureToughness(const Eigen::Vector3d& x) const{ double w = 0.5 + 0.5*cos(f * x.dot(n) + p); // w is in [0, 1] return (1.0-w)*Kc + w*KcHard; } void LayeredMaterialModel::fractureToughnessGradient(Eigen::Vector3d& dKc, const Eigen::Vector3d& x) const{ dKc= (KcHard-Kc)* (-0.5*f)*n*sin( f * x.dot(n) + p ); } // ===================================================================================================== // TubedMaterialModel ================================================================================== double TubedMaterialModel::fractureToughness(const Eigen::Vector3d& x) const{ double f1=15*M_PI, f2=30*M_PI, p1=0.0, p2=0.0; Eigen::Vector3d n1(1.0, 0.0, 0.0), n2(0.0, 0.0, 1.0); n1.normalize(); n2.normalize(); double w = 0.5+0.5*cos(f1*x.dot(n1)+p1)*cos(f2*x.dot(n2)+p2); // w is in [0, 1] //printf("\n %.3le ", (1-w)*Kc + w*KcHard); return (1-w)*Kc + w*KcHard; } void TubedMaterialModel::fractureToughnessGradient(Eigen::Vector3d& dKc, const Eigen::Vector3d& x) const{ double f1=15*M_PI, f2=30*M_PI, p1=0.0, p2=0.0; Eigen::Vector3d n1(1.0, 0.0, 0.0), n2(0.0, 0.0, 1.0); n1.normalize(); n2.normalize(); dKc= (KcHard-Kc)*( -0.5*f1*n1*sin(f1*x.dot(n1)+p1)*cos(f2*x.dot(n2)+p2) -0.5*f2*n2*cos(f1*x.dot(n1)+p1)*sin(f2*x.dot(n2)+p2) ); //printf(" grad( %.3le %.3le %.3le )",dKc[0],dKc[1],dKc[2]); } // ===================================================================================================== // VDBMaterialModel ================================================================================== class VDBMaterialModel::vdbData{ public: vdbData() : ux(1.0,0.0,0.0), uy(0.0,1.0,0.0), uz(0.0,0.0,1.0) {}; vdb::FloatGrid::Ptr toughnessGrid, strengthGrid; vdb::math::Transform::Ptr xform; vdb::Vec3d ux,uy,uz; vdb::math::CoordBBox bbox; }; void VDBMaterialModel::init() const{ haveToughnessMap=false; haveStrengthMap=false; if(data==NULL) data = new vdbData(); vdb::initialize(); vdb::io::File inFile(vdbFile); if(!inFile.open()){ printf("\n%% Failed to open file %s", vdbFile.c_str()); }else{ vdb::GridBase::Ptr baseGrid; if( inFile.hasGrid(kName) ){ baseGrid = inFile.readGrid(kName); data->toughnessGrid=vdb::gridPtrCast(baseGrid); data->bbox = data->toughnessGrid->evalActiveVoxelBoundingBox(); haveToughnessMap=true; } if( kName.compare(sName)) data->strengthGrid = data->toughnessGrid; // share the grid ptr when using the same data for both strength and toughness else if( inFile.hasGrid(sName) ){ baseGrid = inFile.readGrid(sName); data->strengthGrid=vdb::gridPtrCast(baseGrid); data->bbox.expand( data->strengthGrid->evalActiveVoxelBoundingBox() ); haveStrengthMap=true; } inFile.close(); data->xform = vdb::math::Transform::createLinearTransform(voxelSize); //printf("\n%% VDB material model initialized%s%s\n", // haveToughnessMap?", toughness map loaded":"", // haveStrengthMap ? ", strength map loaded":"" //); } } double VDBMaterialModel::tensileStrength(const Eigen::Vector3d& x) const{ if(data==NULL) init(); if(!haveStrengthMap) return Sc; vdb::tools::GridSampler sampler( data->strengthGrid->getConstAccessor(), *(data->xform) ); vdb::Vec3d xi = toPeriodicIndexSpace(x); float gridValue = sampler.isSample(xi) / data->strengthGrid->background(); if(useUDF) gridValue=std::abs(gridValue); return Sc + scale*gridValue; } double VDBMaterialModel::fractureToughness(const Eigen::Vector3d& x) const{ if(data==NULL) init(); if(!haveToughnessMap) return Kc; vdb::tools::GridSampler sampler( data->toughnessGrid->getConstAccessor(), *(data->xform) ); vdb::Vec3d xi = toPeriodicIndexSpace(x); float gridValue = sampler.isSample(xi) / data->toughnessGrid->background(); if(useUDF) gridValue=std::abs(gridValue); //printf("\n eval Kc at (%.3lf,%.3lf,%.3lf) df %.3lf Kc %.3le",x[0],x[1],x[2],gridValue,Kc + scale*gridValue); return Kc + scale*gridValue; } void VDBMaterialModel::fractureToughnessGradient(Eigen::Vector3d& dKc, const Eigen::Vector3d& x) const{ if(data==NULL) init(); if(!haveToughnessMap){ dKc.setZero(); return; } vdb::tools::GridSampler sampler( data->toughnessGrid->getConstAccessor(), *(data->xform) ); float x0,x1,y0,y1,z0,z1, bg=data->toughnessGrid->background(); vdb::Vec3d xi = toPeriodicIndexSpace(x); x0=sampler.isSample(xi-0.25*data->ux) / bg; x1=sampler.isSample(xi+0.25*data->ux) / bg; y0=sampler.isSample(xi-0.25*data->uy) / bg; y1=sampler.isSample(xi+0.25*data->uy) / bg; z0=sampler.isSample(xi-0.25*data->uz) / bg; z1=sampler.isSample(xi+0.25*data->uz) / bg; if(useUDF){ x0=std::abs(x0); x1=std::abs(x1); y0=std::abs(y0); y1=std::abs(y1); z0=std::abs(z0); z1=std::abs(z1); } dKc[0] = scale*(x1-x0)*2.0/voxelSize; dKc[1] = scale*(y1-y0)*2.0/voxelSize; dKc[2] = scale*(z1-z0)*2.0/voxelSize; //if(dKc.norm() > FLT_EPSILON){ // printf("\n x(%.3lf, %.3lf) grad_x %.3le",x0,x1,dKc[0]); // printf("\n y(%.3lf, %.3lf) grad_y %.3le",y0,y1,dKc[1]); // printf("\n z(%.3lf, %.3lf) grad_z %.3le",z0,z1,dKc[2]); //} } template Vec3 VDBMaterialModel::toPeriodicIndexSpace(const Eigen::Vector3d& x) const{ Vec3 xi = data->xform->worldToIndex(Vec3(x[0],x[1],x[2])); //printf("\n pb_map w(%.3lf,%.3lf,%.3lf) -> i(%.1lf,%.1lf,%.1lf)", x[0],x[1],x[2], xi[0],xi[1],xi[2]); vdb::math::BBox box ( data->bbox.min().asVec3d(), data->bbox.max().asVec3d() ); if( box.isInside(xi) ) return xi; xi-=box.min(); // shift min to (0,0,0) //printf("\n--> s(%.1lf,%.1lf,%.1lf)", xi[0],xi[1],xi[2]); xi[0] = std::fmod( xi[0], box.extents()[0] ); if(xi[0]<0.0) xi[0]+=box.extents()[0]; xi[1] = std::fmod( xi[1], box.extents()[1] ); if(xi[1]<0.0) xi[1]+=box.extents()[1]; xi[2] = std::fmod( xi[2], box.extents()[2] ); if(xi[2]<0.0) xi[2]+=box.extents()[2]; //printf("\n--> M(%.1lf,%.1lf,%.1lf), extents (%.1lf,%.1lf,%.1lf)", xi[0],xi[1],xi[2], box.extents()[0],box.extents()[1],box.extents()[2]); xi+=box.min(); // undo shift //printf("\n--> b(%.1lf,%.1lf,%.1lf) in box (%.0lf,%.0lf,%.0lf)-(%.0lf,%.0lf,%.0lf)", xi[0],xi[1],xi[2], box.min()[0],box.min()[1],box.min()[2], box.max()[0],box.max()[1],box.max()[2]); return xi; } // ===================================================================================================== }