Blender V2.61 - r43446
|
00001 00004 // -------------------------------------------------------------------------- 00005 // 00006 // El'Beem - the visual lattice boltzmann freesurface simulator 00007 // All code distributed as part of El'Beem is covered by the version 2 of the 00008 // GNU General Public License. See the file COPYING for details. 00009 // 00010 // Copyright 2008 Nils Thuerey , Richard Keiser, Mark Pauly, Ulrich Ruede 00011 // 00012 // implementation of control particle handling 00013 // 00014 // -------------------------------------------------------------------------- 00015 00016 // indicator for LBM inclusion 00017 #include "ntl_geometrymodel.h" 00018 #include "ntl_world.h" 00019 #include "solver_class.h" 00020 #include "controlparticles.h" 00021 #include "mvmcoords.h" 00022 #include <zlib.h> 00023 00024 #ifndef sqrtf 00025 #define sqrtf sqrt 00026 #endif 00027 00028 // brute force circle test init in initTimeArray 00029 // replaced by mDebugInit 00030 //#define CP_FORCECIRCLEINIT 0 00031 00032 00033 void ControlParticles::initBlenderTest() { 00034 mPartSets.clear(); 00035 00036 ControlParticleSet cps; 00037 mPartSets.push_back(cps); 00038 int setCnt = mPartSets.size()-1; 00039 ControlParticle p; 00040 00041 // set for time zero 00042 mPartSets[setCnt].time = 0.; 00043 00044 // add single particle 00045 p.reset(); 00046 p.pos = LbmVec(0.5, 0.5, -0.5); 00047 mPartSets[setCnt].particles.push_back(p); 00048 00049 // add second set for animation 00050 mPartSets.push_back(cps); 00051 setCnt = mPartSets.size()-1; 00052 mPartSets[setCnt].time = 0.15; 00053 00054 // insert new position 00055 p.reset(); 00056 p.pos = LbmVec(-0.5, -0.5, 0.5); 00057 mPartSets[setCnt].particles.push_back(p); 00058 00059 // applyTrafos(); 00060 initTime(0. , 1.); 00061 } 00062 00063 // blender control object gets converted to mvm flui control object 00064 int ControlParticles::initFromObject(ntlGeometryObjModel *model) { 00065 vector<ntlTriangle> triangles; 00066 vector<ntlVec3Gfx> vertices; 00067 vector<ntlVec3Gfx> normals; 00068 00069 /* 00070 model->loadBobjModel(string(infile)); 00071 00072 model->setLoaded(true); 00073 00074 model->setGeoInitId(gid); 00075 00076 00077 printf("a animated? %d\n", model->getIsAnimated()); 00078 printf("b animated? %d\n", model->getMeshAnimated()); 00079 */ 00080 00081 model->setGeoInitType(FGI_FLUID); 00082 00083 model->getTriangles(mCPSTimeStart, &triangles, &vertices, &normals, 1 ); 00084 // model->applyTransformation(mCPSTimeStart, &vertices, &normals, 0, vertices.size(), true); 00085 00086 // valid mesh? 00087 if(triangles.size() <= 0) { 00088 return 0; 00089 } 00090 00091 ntlRenderGlobals *glob = new ntlRenderGlobals; 00092 ntlScene *genscene = new ntlScene( glob, false ); 00093 genscene->addGeoClass(model); 00094 genscene->addGeoObject(model); 00095 genscene->buildScene(0., false); 00096 char treeFlag = (1<<(4+model->getGeoInitId())); 00097 00098 ntlTree *tree = new ntlTree( 00099 15, 8, // TREEwarning - fixed values for depth & maxtriangles here... 00100 genscene, treeFlag ); 00101 00102 // TODO? use params 00103 ntlVec3Gfx start,end; 00104 model->getExtends(start,end); 00105 /* 00106 printf("start - x: %f, y: %f, z: %f\n", start[0], start[1], start[2]); 00107 printf("end - x: %f, y: %f, z: %f\n", end[0], end[1], end[2]); 00108 printf("mCPSWidth: %f\n"); 00109 */ 00110 LbmFloat width = mCPSWidth; 00111 if(width<=LBM_EPSILON) { errMsg("ControlParticles::initFromMVMCMesh","Invalid mCPSWidth! "<<mCPSWidth); width=mCPSWidth=0.1; } 00112 ntlVec3Gfx org = start+ntlVec3Gfx(width*0.5); 00113 gfxReal distance = -1.; 00114 vector<ntlVec3Gfx> inspos; 00115 00116 // printf("distance: %f, width: %f\n", distance, width); 00117 00118 while(org[2]<end[2]) { 00119 while(org[1]<end[1]) { 00120 while(org[0]<end[0]) { 00121 if(checkPointInside(tree, org, distance)) { 00122 inspos.push_back(org); 00123 } 00124 // TODO optimize, use distance 00125 org[0] += width; 00126 } 00127 org[1] += width; 00128 org[0] = start[0]; 00129 } 00130 org[2] += width; 00131 org[1] = start[1]; 00132 } 00133 00134 // printf("inspos.size(): %d\n", inspos.size()); 00135 00136 MeanValueMeshCoords mvm; 00137 mvm.calculateMVMCs(vertices,triangles, inspos, mCPSWeightFac); 00138 vector<ntlVec3Gfx> ninspos; 00139 mvm.transfer(vertices, ninspos); 00140 00141 // init first set, check dist 00142 ControlParticleSet firstcps; //T 00143 mPartSets.push_back(firstcps); 00144 mPartSets[mPartSets.size()-1].time = mCPSTimeStart; 00145 vector<bool> useCP; 00146 00147 for(int i=0; i<(int)inspos.size(); i++) { 00148 ControlParticle p; p.reset(); 00149 p.pos = vec2L(inspos[i]); 00150 00151 bool usecpv = true; 00152 00153 mPartSets[mPartSets.size()-1].particles.push_back(p); 00154 useCP.push_back(usecpv); 00155 } 00156 00157 // init further sets, temporal mesh sampling 00158 double tsampling = mCPSTimestep; 00159 // printf("tsampling: %f, ninspos.size(): %d, mCPSTimeEnd: %f\n", tsampling, ninspos.size(), mCPSTimeEnd); 00160 00161 int tcnt=0; 00162 for(double t=mCPSTimeStart+tsampling; ((t<mCPSTimeEnd) && (ninspos.size()>0.)); t+=tsampling) { 00163 ControlParticleSet nextcps; //T 00164 mPartSets.push_back(nextcps); 00165 mPartSets[mPartSets.size()-1].time = (gfxReal)t; 00166 00167 vertices.clear(); triangles.clear(); normals.clear(); 00168 model->getTriangles(t, &triangles, &vertices, &normals, 1 ); 00169 mvm.transfer(vertices, ninspos); 00170 00171 tcnt++; 00172 for(size_t i=0; i < ninspos.size(); i++) { 00173 00174 if(useCP[i]) { 00175 ControlParticle p; p.reset(); 00176 p.pos = vec2L(ninspos[i]); 00177 mPartSets[mPartSets.size()-1].particles.push_back(p); 00178 } 00179 } 00180 } 00181 00182 model->setGeoInitType(FGI_CONTROL); 00183 00184 delete tree; 00185 delete genscene; 00186 delete glob; 00187 00188 // do reverse here 00189 if(model->getGeoPartSlipValue()) 00190 { 00191 mirrorTime(); 00192 } 00193 00194 return 1; 00195 } 00196 00197 00198 // init all zero / defaults for a single particle 00199 void ControlParticle::reset() { 00200 pos = LbmVec(0.,0.,0.); 00201 vel = LbmVec(0.,0.,0.); 00202 influence = 1.; 00203 size = 1.; 00204 #ifndef LBMDIM 00205 #ifdef MAIN_2D 00206 rotaxis = LbmVec(0.,1.,0.); // SPH xz 00207 #else // MAIN_2D 00208 // 3d - roate in xy plane, vortex 00209 rotaxis = LbmVec(0.,0.,1.); 00210 // 3d - rotate for wave 00211 //rotaxis = LbmVec(0.,1.,0.); 00212 #endif // MAIN_2D 00213 #else // LBMDIM 00214 rotaxis = LbmVec(0.,1.,0.); // LBM xy , is swapped afterwards 00215 #endif // LBMDIM 00216 00217 density = 0.; 00218 densityWeight = 0.; 00219 avgVelAcc = avgVel = LbmVec(0.); 00220 avgVelWeight = 0.; 00221 } 00222 00223 00224 // default preset/empty init 00225 ControlParticles::ControlParticles() : 00226 _influenceTangential(0.f), 00227 _influenceAttraction(0.f), 00228 _influenceVelocity(0.f), 00229 _influenceMaxdist(0.f), 00230 _radiusAtt(1.0f), 00231 _radiusVel(1.0f), 00232 _radiusMinMaxd(2.0f), 00233 _radiusMaxd(3.0f), 00234 _currTime(-1.0), _currTimestep(1.), 00235 _initTimeScale(1.), 00236 _initPartOffset(0.), _initPartScale(1.), 00237 _initLastPartOffset(0.), _initLastPartScale(1.), 00238 _initMirror(""), 00239 _fluidSpacing(1.), _kernelWeight(-1.), 00240 _charLength(1.), _charLengthInv(1.), 00241 mvCPSStart(-10000.), mvCPSEnd(10000.), 00242 mCPSWidth(0.1), mCPSTimestep(0.02), // was 0.05 00243 mCPSTimeStart(0.), mCPSTimeEnd(0.5), mCPSWeightFac(1.), 00244 mDebugInit(0) 00245 { 00246 _radiusAtt = 0.15f; 00247 _radiusVel = 0.15f; 00248 _radiusMinMaxd = 0.16f; 00249 _radiusMaxd = 0.3; 00250 00251 _influenceAttraction = 0.f; 00252 _influenceTangential = 0.f; 00253 _influenceVelocity = 0.f; 00254 // 3d tests */ 00255 } 00256 00257 00258 00259 ControlParticles::~ControlParticles() { 00260 // nothing to do... 00261 } 00262 00263 LbmFloat ControlParticles::getControlTimStart() { 00264 if(mPartSets.size()>0) { return mPartSets[0].time; } 00265 return -1000.; 00266 } 00267 LbmFloat ControlParticles::getControlTimEnd() { 00268 if(mPartSets.size()>0) { return mPartSets[mPartSets.size()-1].time; } 00269 return -1000.; 00270 } 00271 00272 // calculate for delta t 00273 void ControlParticles::setInfluenceVelocity(LbmFloat set, LbmFloat dt) { 00274 const LbmFloat dtInter = 0.01; 00275 LbmFloat facFv = 1.-set; //cparts->getInfluenceVelocity(); 00276 // mLevel[mMaxRefine].timestep 00277 LbmFloat facNv = (LbmFloat)( 1.-pow( (double)facFv, (double)(dt/dtInter)) ); 00278 //errMsg("vwcalc","ts:"<<dt<< " its:"<<(dt/dtInter) <<" fv"<<facFv<<" nv"<<facNv<<" test:"<< pow( (double)(1.-facNv),(double)(dtInter/dt)) ); 00279 _influenceVelocity = facNv; 00280 } 00281 00282 int ControlParticles::initExampleSet() 00283 { 00284 // unused 00285 return 0; 00286 } 00287 00288 int ControlParticles::getTotalSize() 00289 { 00290 int s=0; 00291 for(int i=0; i<(int)mPartSets.size(); i++) { 00292 s+= mPartSets[i].particles.size(); 00293 } 00294 return s; 00295 } 00296 00297 // -------------------------------------------------------------------------- 00298 // load positions & timing from text file 00299 // WARNING - make sure file has unix format, no win/dos linefeeds... 00300 #define LINE_LEN 100 00301 int ControlParticles::initFromTextFile(string filename) 00302 { 00303 /* 00304 const bool debugRead = false; 00305 char line[LINE_LEN]; 00306 line[LINE_LEN-1] = '\0'; 00307 mPartSets.clear(); 00308 if(filename.size()<2) return 0; 00309 00310 // HACK , use "cparts" suffix as old 00311 // e.g. "cpart2" as new 00312 if(filename[ filename.size()-1 ]=='s') { 00313 return initFromTextFileOld(filename); 00314 } 00315 00316 FILE *infile = fopen(filename.c_str(), "r"); 00317 if(!infile) { 00318 errMsg("ControlParticles::initFromTextFile","unable to open '"<<filename<<"' " ); 00319 // try to open as gz sequence 00320 if(initFromBinaryFile(filename)) { return 1; } 00321 // try mesh MVCM generation 00322 if(initFromMVCMesh(filename)) { return 1; } 00323 // failed... 00324 return 0; 00325 } 00326 00327 int haveNo = false; 00328 int haveScale = false; 00329 int haveTime = false; 00330 int noParts = -1; 00331 int partCnt = 0; 00332 int setCnt = 0; 00333 //ControlParticle p; p.reset(); 00334 // scale times by constant factor while reading 00335 LbmFloat timeScale= 1.0; 00336 int lineCnt = 0; 00337 bool abortParse = false; 00338 #define LASTCP mPartSets[setCnt].particles[ mPartSets[setCnt].particles.size()-1 ] 00339 00340 while( (!feof(infile)) && (!abortParse)) { 00341 lineCnt++; 00342 fgets(line, LINE_LEN, infile); 00343 00344 //if(debugRead) printf("\nDEBUG%d r '%s'\n",lineCnt, line); 00345 if(!line) continue; 00346 size_t len = strlen(line); 00347 00348 // skip empty lines and comments (#,//) 00349 if(len<1) continue; 00350 if( (line[0]=='#') || (line[0]=='\n') ) continue; 00351 if((len>1) && (line[0]=='/' && line[1]=='/')) continue; 00352 00353 // debug remove newline 00354 if((len>=1)&&(line[len-1]=='\n')) line[len-1]='\0'; 00355 00356 switch(line[0]) { 00357 00358 case 'N': { // total number of particles, more for debugging... 00359 noParts = atoi(line+2); 00360 if(noParts<=0) { 00361 errMsg("ControlParticles::initFromTextFile","file '"<<filename<<"' - invalid no of particles "<<noParts); 00362 mPartSets.clear(); fclose(infile); return 0; 00363 } 00364 if(debugRead) printf("CPDEBUG%d no parts '%d'\n",lineCnt, noParts ); 00365 haveNo = true; 00366 } break; 00367 00368 case 'T': { // global time scale 00369 timeScale *= (LbmFloat)atof(line+2); 00370 if(debugRead) printf("ControlParticles::initFromTextFile - line %d , set timescale '%f', org %f\n",lineCnt, timeScale , _initTimeScale); 00371 if(timeScale==0.) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error: timescale = 0.! reseting to 1 ...\n",lineCnt); timeScale=1.; } 00372 haveScale = true; 00373 } break; 00374 00375 case 'I': { // influence settings, overrides others as of now... 00376 float val = (LbmFloat)atof(line+3); 00377 const char *setvar = "[invalid]"; 00378 switch(line[1]) { 00379 //case 'f': { _influenceFalloff = val; setvar = "falloff"; } break; 00380 case 't': { _influenceTangential = val; setvar = "tangential"; } break; 00381 case 'a': { _influenceAttraction = val; setvar = "attraction"; } break; 00382 case 'v': { _influenceVelocity = val; setvar = "velocity"; } break; 00383 case 'm': { _influenceMaxdist = val; setvar = "maxdist"; } break; 00384 default: 00385 fprintf(stdout,"ControlParticles::initFromTextFile (%s) - line %d , invalid influence setting %c, %f\n",filename.c_str() ,lineCnt, line[1], val); 00386 } 00387 if(debugRead) printf("CPDEBUG%d set influence '%s'=%f \n",lineCnt, setvar, val); 00388 } break; 00389 00390 case 'R': { // radius settings, overrides others as of now... 00391 float val = (LbmFloat)atof(line+3); 00392 const char *setvar = "[invalid]"; 00393 switch(line[1]) { 00394 case 'a': { _radiusAtt = val; setvar = "r_attraction"; } break; 00395 case 'v': { _radiusVel = val; setvar = "r_velocity"; } break; 00396 case 'm': { _radiusMaxd = val; setvar = "r_maxdist"; } break; 00397 default: 00398 fprintf(stdout,"ControlParticles::initFromTextFile (%s) - line %d , invalid influence setting %c, %f\n",filename.c_str() ,lineCnt, line[1], val); 00399 } 00400 if(debugRead) printf("CPDEBUG%d set influence '%s'=%f \n",lineCnt, setvar, val); 00401 } break; 00402 00403 case 'S': { // new particle set at time T 00404 ControlParticleSet cps; 00405 mPartSets.push_back(cps); 00406 setCnt = (int)mPartSets.size()-1; 00407 00408 LbmFloat val = (LbmFloat)atof(line+2); 00409 mPartSets[setCnt].time = val * timeScale; 00410 if(debugRead) printf("CPDEBUG%d new set, time '%f', %d\n",lineCnt, mPartSets[setCnt].time, setCnt ); 00411 haveTime = true; 00412 partCnt = -1; 00413 } break; 00414 00415 case 'P': // new particle with pos 00416 case 'n': { // new particle without pos 00417 if((!haveTime)||(setCnt<0)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error: set missing!\n",lineCnt); abortParse=true; break; } 00418 partCnt++; 00419 if(partCnt>=noParts) { 00420 if(debugRead) printf("CPDEBUG%d partset done \n",lineCnt); 00421 haveTime = false; 00422 } else { 00423 ControlParticle p; p.reset(); 00424 mPartSets[setCnt].particles.push_back(p); 00425 } 00426 } 00427 // only new part, or new with pos? 00428 if(line[0] == 'n') break; 00429 00430 // particle properties 00431 00432 case 'p': { // new particle set at time T 00433 if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|p: particle missing!\n",lineCnt); abortParse=true; break; } 00434 float px=0.,py=0.,pz=0.; 00435 if( sscanf(line+2,"%f %f %f",&px,&py,&pz) != 3) { 00436 fprintf(stdout,"CPDEBUG%d, unable to parse position!\n",lineCnt); abortParse=true; break; 00437 } 00438 if(!(finite(px)&&finite(py)&&finite(pz))) { px=py=pz=0.; } 00439 LASTCP.pos[0] = px; 00440 LASTCP.pos[1] = py; 00441 LASTCP.pos[2] = pz; 00442 if(debugRead) printf("CPDEBUG%d part%d,%d: position %f,%f,%f \n",lineCnt,setCnt,partCnt, px,py,pz); 00443 } break; 00444 00445 case 's': { // particle size 00446 if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|s: particle missing!\n",lineCnt); abortParse=true; break; } 00447 float ps=1.; 00448 if( sscanf(line+2,"%f",&ps) != 1) { 00449 fprintf(stdout,"CPDEBUG%d, unable to parse size!\n",lineCnt); abortParse=true; break; 00450 } 00451 if(!(finite(ps))) { ps=0.; } 00452 LASTCP.size = ps; 00453 if(debugRead) printf("CPDEBUG%d part%d,%d: size %f \n",lineCnt,setCnt,partCnt, ps); 00454 } break; 00455 00456 case 'i': { // particle influence 00457 if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|i: particle missing!\n",lineCnt); abortParse=true; break; } 00458 float pinf=1.; 00459 if( sscanf(line+2,"%f",&pinf) != 1) { 00460 fprintf(stdout,"CPDEBUG%d, unable to parse size!\n",lineCnt); abortParse=true; break; 00461 } 00462 if(!(finite(pinf))) { pinf=0.; } 00463 LASTCP.influence = pinf; 00464 if(debugRead) printf("CPDEBUG%d part%d,%d: influence %f \n",lineCnt,setCnt,partCnt, pinf); 00465 } break; 00466 00467 case 'a': { // rotation axis 00468 if((!haveTime)||(setCnt<0)||(mPartSets[setCnt].particles.size()<1)) { fprintf(stdout,"ControlParticles::initFromTextFile - line %d ,error|a: particle missing!\n",lineCnt); abortParse=true; break; } 00469 float px=0.,py=0.,pz=0.; 00470 if( sscanf(line+2,"%f %f %f",&px,&py,&pz) != 3) { 00471 fprintf(stdout,"CPDEBUG%d, unable to parse rotaxis!\n",lineCnt); abortParse=true; break; 00472 } 00473 if(!(finite(px)&&finite(py)&&finite(pz))) { px=py=pz=0.; } 00474 LASTCP.rotaxis[0] = px; 00475 LASTCP.rotaxis[1] = py; 00476 LASTCP.rotaxis[2] = pz; 00477 if(debugRead) printf("CPDEBUG%d part%d,%d: rotaxis %f,%f,%f \n",lineCnt,setCnt,partCnt, px,py,pz); 00478 } break; 00479 00480 00481 default: 00482 if(debugRead) printf("CPDEBUG%d ignored: '%s'\n",lineCnt, line ); 00483 break; 00484 } 00485 } 00486 if(debugRead && abortParse) printf("CPDEBUG aborted parsing after set... %d\n",(int)mPartSets.size() ); 00487 00488 // sanity check 00489 for(int i=0; i<(int)mPartSets.size(); i++) { 00490 if( (int)mPartSets[i].particles.size()!=noParts) { 00491 fprintf(stdout,"ControlParticles::initFromTextFile (%s) - invalid no of particles in set %d, is:%d, shouldbe:%d \n",filename.c_str() ,i,(int)mPartSets[i].particles.size(), noParts); 00492 mPartSets.clear(); 00493 fclose(infile); 00494 return 0; 00495 } 00496 } 00497 00498 // print stats 00499 printf("ControlParticles::initFromTextFile (%s): Read %d sets, each %d particles\n",filename.c_str() , 00500 (int)mPartSets.size(), noParts ); 00501 if(mPartSets.size()>0) { 00502 printf("ControlParticles::initFromTextFile (%s): Time: %f,%f\n",filename.c_str() ,mPartSets[0].time, mPartSets[mPartSets.size()-1].time ); 00503 } 00504 00505 // done... 00506 fclose(infile); 00507 applyTrafos(); 00508 */ 00509 return 1; 00510 } 00511 00512 00513 int ControlParticles::initFromTextFileOld(string filename) 00514 { 00515 /* 00516 const bool debugRead = false; 00517 char line[LINE_LEN]; 00518 line[LINE_LEN-1] = '\0'; 00519 mPartSets.clear(); 00520 if(filename.size()<1) return 0; 00521 00522 FILE *infile = fopen(filename.c_str(), "r"); 00523 if(!infile) { 00524 fprintf(stdout,"ControlParticles::initFromTextFileOld - unable to open '%s'\n",filename.c_str() ); 00525 return 0; 00526 } 00527 00528 int haveNo = false; 00529 int haveScale = false; 00530 int haveTime = false; 00531 int noParts = -1; 00532 int coordCnt = 0; 00533 int partCnt = 0; 00534 int setCnt = 0; 00535 ControlParticle p; p.reset(); 00536 // scale times by constant factor while reading 00537 LbmFloat timeScale= 1.0; 00538 int lineCnt = 0; 00539 00540 while(!feof(infile)) { 00541 lineCnt++; 00542 fgets(line, LINE_LEN, infile); 00543 00544 if(debugRead) printf("\nDEBUG%d r '%s'\n",lineCnt, line); 00545 00546 if(!line) continue; 00547 size_t len = strlen(line); 00548 00549 // skip empty lines and comments (#,//) 00550 if(len<1) continue; 00551 if( (line[0]=='#') || (line[0]=='\n') ) continue; 00552 if((len>1) && (line[0]=='/' && line[1]=='/')) continue; 00553 00554 // debug remove newline 00555 if((len>=1)&&(line[len-1]=='\n')) line[len-1]='\0'; 00556 00557 // first read no. of particles 00558 if(!haveNo) { 00559 noParts = atoi(line); 00560 if(noParts<=0) { 00561 fprintf(stdout,"ControlParticles::initFromTextFileOld - invalid no of particles %d\n",noParts); 00562 mPartSets.clear(); 00563 fclose(infile); 00564 return 0; 00565 } 00566 if(debugRead) printf("DEBUG%d noparts '%d'\n",lineCnt, noParts ); 00567 haveNo = true; 00568 } 00569 00570 // then read time scale 00571 else if(!haveScale) { 00572 timeScale *= (LbmFloat)atof(line); 00573 if(debugRead) printf("DEBUG%d tsc '%f', org %f\n",lineCnt, timeScale , _initTimeScale); 00574 haveScale = true; 00575 } 00576 00577 // then get set time 00578 else if(!haveTime) { 00579 ControlParticleSet cps; 00580 mPartSets.push_back(cps); 00581 setCnt = (int)mPartSets.size()-1; 00582 00583 LbmFloat val = (LbmFloat)atof(line); 00584 mPartSets[setCnt].time = val * timeScale; 00585 if(debugRead) printf("DEBUG%d time '%f', %d\n",lineCnt, mPartSets[setCnt].time, setCnt ); 00586 haveTime = true; 00587 } 00588 00589 // default read all parts 00590 else { 00591 LbmFloat val = (LbmFloat)atof(line); 00592 if(debugRead) printf("DEBUG: l%d s%d,particle%d '%f' %d,%d/%d\n",lineCnt,(int)mPartSets.size(),(int)mPartSets[setCnt].particles.size(), val ,coordCnt,partCnt,noParts); 00593 p.pos[coordCnt] = val; 00594 coordCnt++; 00595 if(coordCnt>=3) { 00596 mPartSets[setCnt].particles.push_back(p); 00597 p.reset(); 00598 coordCnt=0; 00599 partCnt++; 00600 } 00601 if(partCnt>=noParts) { 00602 partCnt = 0; 00603 haveTime = false; 00604 } 00605 //if(debugRead) printf("DEBUG%d par2 %d,%d/%d\n",lineCnt, coordCnt,partCnt,noParts); 00606 } 00607 //read pos, vel ... 00608 } 00609 00610 // sanity check 00611 for(int i=0; i<(int)mPartSets.size(); i++) { 00612 if( (int)mPartSets[i].particles.size()!=noParts) { 00613 fprintf(stdout,"ControlParticles::initFromTextFileOld - invalid no of particles in set %d, is:%d, shouldbe:%d \n",i,(int)mPartSets[i].particles.size(), noParts); 00614 mPartSets.clear(); 00615 fclose(infile); 00616 return 0; 00617 } 00618 } 00619 // print stats 00620 printf("ControlParticles::initFromTextFileOld: Read %d sets, each %d particles\n", 00621 (int)mPartSets.size(), noParts ); 00622 if(mPartSets.size()>0) { 00623 printf("ControlParticles::initFromTextFileOld: Time: %f,%f\n",mPartSets[0].time, mPartSets[mPartSets.size()-1].time ); 00624 } 00625 00626 // done... 00627 fclose(infile); 00628 applyTrafos(); 00629 */ 00630 return 1; 00631 } 00632 00633 // load positions & timing from gzipped binary file 00634 int ControlParticles::initFromBinaryFile(string filename) { 00635 mPartSets.clear(); 00636 if(filename.size()<1) return 0; 00637 int fileNotFound=0; 00638 int fileFound=0; 00639 char ofile[256]; 00640 00641 for(int set=0; ((set<10000)&&(fileNotFound<10)); set++) { 00642 snprintf(ofile,256,"%s%04d.gz",filename.c_str(),set); 00643 //errMsg("ControlParticle::initFromBinaryFile","set"<<set<<" notf"<<fileNotFound<<" ff"<<fileFound); 00644 00645 gzFile gzf; 00646 gzf = gzopen(ofile, "rb"); 00647 if (!gzf) { 00648 //errMsg("ControlParticles::initFromBinaryFile","Unable to open file for reading '"<<ofile<<"' "); 00649 fileNotFound++; 00650 continue; 00651 } 00652 fileNotFound=0; 00653 fileFound++; 00654 00655 ControlParticleSet cps; 00656 mPartSets.push_back(cps); 00657 int setCnt = (int)mPartSets.size()-1; 00658 //LbmFloat val = (LbmFloat)atof(line+2); 00659 mPartSets[setCnt].time = (gfxReal)set; 00660 00661 int totpart = 0; 00662 gzread(gzf, &totpart, sizeof(totpart)); 00663 00664 for(int a=0; a<totpart; a++) { 00665 int ptype=0; 00666 float psize=0.0; 00667 ntlVec3Gfx ppos,pvel; 00668 gzread(gzf, &ptype, sizeof( ptype )); 00669 gzread(gzf, &psize, sizeof( float )); 00670 00671 for(int j=0; j<3; j++) { gzread(gzf, &ppos[j], sizeof( float )); } 00672 for(int j=0; j<3; j++) { gzread(gzf, &pvel[j], sizeof( float )); } 00673 00674 ControlParticle p; 00675 p.reset(); 00676 p.pos = vec2L(ppos); 00677 mPartSets[setCnt].particles.push_back(p); 00678 } 00679 00680 gzclose(gzf); 00681 //errMsg("ControlParticle::initFromBinaryFile","Read set "<<ofile<<", #"<<mPartSets[setCnt].particles.size() ); // DEBUG 00682 } // sets 00683 00684 if(fileFound==0) return 0; 00685 applyTrafos(); 00686 return 1; 00687 } 00688 00689 int globCPIProblems =0; 00690 bool ControlParticles::checkPointInside(ntlTree *tree, ntlVec3Gfx org, gfxReal &distance) { 00691 // warning - stripped down version of geoInitCheckPointInside 00692 const int globGeoInitDebug = 0; 00693 const int flags = FGI_FLUID; 00694 org += ntlVec3Gfx(0.0001); 00695 ntlVec3Gfx dir = ntlVec3Gfx(1.0, 0.0, 0.0); 00696 int OId = -1; 00697 ntlRay ray(org, dir, 0, 1.0, NULL); 00698 bool done = false; 00699 bool inside = false; 00700 int mGiObjInside = 0; 00701 LbmFloat mGiObjDistance = -1.0; 00702 LbmFloat giObjFirstHistSide = 0; 00703 00704 // if not inside, return distance to first hit 00705 gfxReal firstHit=-1.0; 00706 int firstOId = -1; 00707 if(globGeoInitDebug) errMsg("IIIstart"," isect "<<org); 00708 00709 while(!done) { 00710 // find first inside intersection 00711 ntlTriangle *triIns = NULL; 00712 distance = -1.0; 00713 ntlVec3Gfx normal(0.0); 00714 tree->intersectX(ray,distance,normal, triIns, flags, true); 00715 if(triIns) { 00716 ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance; 00717 LbmFloat orientation = dot(normal, dir); 00718 OId = triIns->getObjectId(); 00719 if(orientation<=0.0) { 00720 // outside hit 00721 normal *= -1.0; 00722 mGiObjInside++; 00723 if(giObjFirstHistSide==0) giObjFirstHistSide = 1; 00724 if(globGeoInitDebug) errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation); 00725 } else { 00726 // inside hit 00727 mGiObjInside++; 00728 if(mGiObjDistance<0.0) mGiObjDistance = distance; 00729 if(globGeoInitDebug) errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation); 00730 if(giObjFirstHistSide==0) giObjFirstHistSide = -1; 00731 } 00732 norg += normal * getVecEpsilon(); 00733 ray = ntlRay(norg, dir, 0, 1.0, NULL); 00734 // remember first hit distance, in case we're not 00735 // inside anything 00736 if(firstHit<0.0) { 00737 firstHit = distance; 00738 firstOId = OId; 00739 } 00740 } else { 00741 // no more intersections... return false 00742 done = true; 00743 } 00744 } 00745 00746 distance = -1.0; 00747 if(mGiObjInside>0) { 00748 bool mess = false; 00749 if((mGiObjInside%2)==1) { 00750 if(giObjFirstHistSide != -1) mess=true; 00751 } else { 00752 if(giObjFirstHistSide != 1) mess=true; 00753 } 00754 if(mess) { 00755 // ? 00756 //errMsg("IIIproblem","At "<<org<<" obj inside:"<<mGiObjInside<<" firstside:"<<giObjFirstHistSide ); 00757 globCPIProblems++; 00758 mGiObjInside++; // believe first hit side... 00759 } 00760 } 00761 00762 if(globGeoInitDebug) errMsg("CHIII"," ins="<<mGiObjInside<<" t"<<mGiObjDistance<<" d"<<distance); 00763 if(((mGiObjInside%2)==1)&&(mGiObjDistance>0.0)) { 00764 if( (distance<0.0) || // first intersection -> good 00765 ((distance>0.0)&&(distance>mGiObjDistance)) // more than one intersection -> use closest one 00766 ) { 00767 distance = mGiObjDistance; 00768 OId = 0; 00769 inside = true; 00770 } 00771 } 00772 00773 if(!inside) { 00774 distance = firstHit; 00775 OId = firstOId; 00776 } 00777 if(globGeoInitDebug) errMsg("CHIII","ins"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId); 00778 00779 return inside; 00780 } 00781 int ControlParticles::initFromMVCMesh(string filename) { 00782 myTime_t mvmstart = getTime(); 00783 ntlGeometryObjModel *model = new ntlGeometryObjModel(); 00784 int gid=1; 00785 char infile[256]; 00786 vector<ntlTriangle> triangles; 00787 vector<ntlVec3Gfx> vertices; 00788 vector<ntlVec3Gfx> normals; 00789 snprintf(infile,256,"%s.bobj.gz", filename.c_str() ); 00790 model->loadBobjModel(string(infile)); 00791 model->setLoaded(true); 00792 model->setGeoInitId(gid); 00793 model->setGeoInitType(FGI_FLUID); 00794 debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"infile:"<<string(infile) ,4); 00795 00796 //getTriangles(double t, vector<ntlTriangle> *triangles, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, int objectId ); 00797 model->getTriangles(mCPSTimeStart, &triangles, &vertices, &normals, 1 ); 00798 debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG," tris:"<<triangles.size()<<" verts:"<<vertices.size()<<" norms:"<<normals.size() , 2); 00799 00800 // valid mesh? 00801 if(triangles.size() <= 0) { 00802 return 0; 00803 } 00804 00805 ntlRenderGlobals *glob = new ntlRenderGlobals; 00806 ntlScene *genscene = new ntlScene( glob, false ); 00807 genscene->addGeoClass(model); 00808 genscene->addGeoObject(model); 00809 genscene->buildScene(0., false); 00810 char treeFlag = (1<<(4+gid)); 00811 00812 ntlTree *tree = new ntlTree( 00813 15, 8, // TREEwarning - fixed values for depth & maxtriangles here... 00814 genscene, treeFlag ); 00815 00816 // TODO? use params 00817 ntlVec3Gfx start,end; 00818 model->getExtends(start,end); 00819 00820 LbmFloat width = mCPSWidth; 00821 if(width<=LBM_EPSILON) { errMsg("ControlParticles::initFromMVMCMesh","Invalid mCPSWidth! "<<mCPSWidth); width=mCPSWidth=0.1; } 00822 ntlVec3Gfx org = start+ntlVec3Gfx(width*0.5); 00823 gfxReal distance = -1.; 00824 vector<ntlVec3Gfx> inspos; 00825 int approxmax = (int)( ((end[0]-start[0])/width)*((end[1]-start[1])/width)*((end[2]-start[2])/width) ); 00826 00827 debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"start"<<start<<" end"<<end<<" w="<<width<<" maxp:"<<approxmax, 5); 00828 while(org[2]<end[2]) { 00829 while(org[1]<end[1]) { 00830 while(org[0]<end[0]) { 00831 if(checkPointInside(tree, org, distance)) { 00832 inspos.push_back(org); 00833 //inspos.push_back(org+ntlVec3Gfx(width)); 00834 //inspos.push_back(start+end*0.5); 00835 } 00836 // TODO optimize, use distance 00837 org[0] += width; 00838 } 00839 org[1] += width; 00840 org[0] = start[0]; 00841 } 00842 org[2] += width; 00843 org[1] = start[1]; 00844 } 00845 debMsgStd("ControlParticles::initFromMVMCMesh",DM_MSG,"points: "<<inspos.size()<<" initproblems: "<<globCPIProblems,5 ); 00846 00847 MeanValueMeshCoords mvm; 00848 mvm.calculateMVMCs(vertices,triangles, inspos, mCPSWeightFac); 00849 vector<ntlVec3Gfx> ninspos; 00850 mvm.transfer(vertices, ninspos); 00851 00852 // init first set, check dist 00853 ControlParticleSet firstcps; //T 00854 mPartSets.push_back(firstcps); 00855 mPartSets[mPartSets.size()-1].time = (gfxReal)0.; 00856 vector<bool> useCP; 00857 bool debugPos=false; 00858 00859 for(int i=0; i<(int)inspos.size(); i++) { 00860 ControlParticle p; p.reset(); 00861 p.pos = vec2L(inspos[i]); 00862 //errMsg("COMP "," "<<inspos[i]<<" vs "<<ninspos[i] ); 00863 double cpdist = norm(inspos[i]-ninspos[i]); 00864 bool usecpv = true; 00865 if(debugPos) errMsg("COMP "," "<<cpdist<<usecpv); 00866 00867 mPartSets[mPartSets.size()-1].particles.push_back(p); 00868 useCP.push_back(usecpv); 00869 } 00870 00871 // init further sets, temporal mesh sampling 00872 double tsampling = mCPSTimestep; 00873 int totcnt = (int)( (mCPSTimeEnd-mCPSTimeStart)/tsampling ), tcnt=0; 00874 for(double t=mCPSTimeStart+tsampling; ((t<mCPSTimeEnd) && (ninspos.size()>0.)); t+=tsampling) { 00875 ControlParticleSet nextcps; //T 00876 mPartSets.push_back(nextcps); 00877 mPartSets[mPartSets.size()-1].time = (gfxReal)t; 00878 00879 vertices.clear(); triangles.clear(); normals.clear(); 00880 model->getTriangles(t, &triangles, &vertices, &normals, 1 ); 00881 mvm.transfer(vertices, ninspos); 00882 if(tcnt%(totcnt/10)==1) debMsgStd("MeanValueMeshCoords::calculateMVMCs",DM_MSG,"Transferring animation, frame: "<<tcnt<<"/"<<totcnt,5 ); 00883 tcnt++; 00884 for(int i=0; i<(int)ninspos.size(); i++) { 00885 if(debugPos) errMsg("COMP "," "<<norm(inspos[i]-ninspos[i]) ); 00886 if(useCP[i]) { 00887 ControlParticle p; p.reset(); 00888 p.pos = vec2L(ninspos[i]); 00889 mPartSets[mPartSets.size()-1].particles.push_back(p); 00890 } 00891 } 00892 } 00893 00894 applyTrafos(); 00895 00896 myTime_t mvmend = getTime(); 00897 debMsgStd("ControlParticle::initFromMVMCMesh",DM_MSG,"t:"<<getTimeString(mvmend-mvmstart)<<" ",7 ); 00898 delete tree; 00899 delete genscene; 00900 delete glob; 00901 //exit(1); // DEBUG 00902 return 1; 00903 } 00904 00905 #define TRISWAP(v,a,b) { LbmFloat tmp = (v)[b]; (v)[b]=(v)[a]; (v)[a]=tmp; } 00906 #define TRISWAPALL(v,a,b) { \ 00907 TRISWAP( (v).pos ,a,b ); \ 00908 TRISWAP( (v).vel ,a,b ); \ 00909 TRISWAP( (v).rotaxis ,a,b ); } 00910 00911 // helper function for LBM 2D -> swap Y and Z components everywhere 00912 void ControlParticles::swapCoords(int a, int b) { 00913 //return; 00914 for(int i=0; i<(int)mPartSets.size(); i++) { 00915 for(int j=0; j<(int)mPartSets[i].particles.size(); j++) { 00916 TRISWAPALL( mPartSets[i].particles[j],a,b ); 00917 } 00918 } 00919 } 00920 00921 // helper function for LBM 2D -> mirror time 00922 void ControlParticles::mirrorTime() { 00923 LbmFloat maxtime = mPartSets[mPartSets.size()-1].time; 00924 const bool debugTimeswap = false; 00925 00926 for(int i=0; i<(int)mPartSets.size(); i++) { 00927 mPartSets[i].time = maxtime - mPartSets[i].time; 00928 } 00929 00930 for(int i=0; i<(int)mPartSets.size()/2; i++) { 00931 ControlParticleSet cps = mPartSets[i]; 00932 if(debugTimeswap) errMsg("TIMESWAP", " s"<<i<<","<<mPartSets[i].time<<" and s"<<(mPartSets.size()-1-i)<<","<< mPartSets[mPartSets.size()-1-i].time <<" mt:"<<maxtime ); 00933 mPartSets[i] = mPartSets[mPartSets.size()-1-i]; 00934 mPartSets[mPartSets.size()-1-i] = cps; 00935 } 00936 00937 for(int i=0; i<(int)mPartSets.size(); i++) { 00938 if(debugTimeswap) errMsg("TIMESWAP", "done: s"<<i<<","<<mPartSets[i].time<<" "<<mPartSets[i].particles.size() ); 00939 } 00940 } 00941 00942 // apply init transformations 00943 void ControlParticles::applyTrafos() { 00944 // apply trafos 00945 for(int i=0; i<(int)mPartSets.size(); i++) { 00946 mPartSets[i].time *= _initTimeScale; 00947 /*for(int j=0; j<(int)mPartSets[i].particles.size(); j++) { 00948 for(int k=0; k<3; k++) { 00949 mPartSets[i].particles[j].pos[k] *= _initPartScale[k]; 00950 mPartSets[i].particles[j].pos[k] += _initPartOffset[k]; 00951 } 00952 } now done in initarray */ 00953 } 00954 00955 // mirror coords... 00956 for(int l=0; l<(int)_initMirror.length(); l++) { 00957 switch(_initMirror[l]) { 00958 case 'X': 00959 case 'x': 00960 //printf("ControlParticles::applyTrafos - mirror x\n"); 00961 swapCoords(1,2); 00962 break; 00963 case 'Y': 00964 case 'y': 00965 //printf("ControlParticles::applyTrafos - mirror y\n"); 00966 swapCoords(0,2); 00967 break; 00968 case 'Z': 00969 case 'z': 00970 //printf("ControlParticles::applyTrafos - mirror z\n"); 00971 swapCoords(0,1); 00972 break; 00973 case 'T': 00974 case 't': 00975 //printf("ControlParticles::applyTrafos - mirror time\n"); 00976 mirrorTime(); 00977 break; 00978 case ' ': 00979 case '-': 00980 case '\n': 00981 break; 00982 default: 00983 //printf("ControlParticles::applyTrafos - mirror unknown %c !?\n", _initMirror[l] ); 00984 break; 00985 } 00986 } 00987 00988 // reset 2d positions 00989 #if (CP_PROJECT2D==1) && ( defined(MAIN_2D) || LBMDIM==2 ) 00990 for(size_t j=0; j<mPartSets.size(); j++) 00991 for(size_t i=0; i<mPartSets[j].particles.size(); i++) { 00992 // DEBUG 00993 mPartSets[j].particles[i].pos[1] = 0.f; 00994 } 00995 #endif 00996 00997 #if defined(LBMDIM) 00998 //? if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){ 00999 // gui control test, don swap... 01000 //? } else { 01001 //? swapCoords(1,2); // LBM 2D -> swap Y and Z components everywhere 01002 //? } 01003 #endif 01004 01005 initTime(0.f, 0.f); 01006 } 01007 01008 #undef TRISWAP 01009 01010 // -------------------------------------------------------------------------- 01011 // init for a given time 01012 void ControlParticles::initTime(LbmFloat t, LbmFloat dt) 01013 { 01014 //fprintf(stdout, "CPINITTIME init %f\n",t); 01015 _currTime = t; 01016 if(mPartSets.size()<1) return; 01017 01018 // init zero velocities 01019 initTimeArray(t, _particles); 01020 01021 // calculate velocities from prev. timestep? 01022 if(dt>0.) { 01023 _currTimestep = dt; 01024 std::vector<ControlParticle> prevparts; 01025 initTimeArray(t-dt, prevparts); 01026 LbmFloat invdt = 1.0/dt; 01027 for(size_t j=0; j<_particles.size(); j++) { 01028 ControlParticle &p = _particles[j]; 01029 ControlParticle &prevp = prevparts[j]; 01030 for(int k=0; k<3; k++) { 01031 p.pos[k] *= _initPartScale[k]; 01032 p.pos[k] += _initPartOffset[k]; 01033 prevp.pos[k] *= _initLastPartScale[k]; 01034 prevp.pos[k] += _initLastPartOffset[k]; 01035 } 01036 p.vel = (p.pos - prevp.pos)*invdt; 01037 } 01038 01039 if(0) { 01040 LbmVec avgvel(0.); 01041 for(size_t j=0; j<_particles.size(); j++) { 01042 avgvel += _particles[j].vel; 01043 } 01044 avgvel /= (LbmFloat)_particles.size(); 01045 //fprintf(stdout," AVGVEL %f,%f,%f \n",avgvel[0],avgvel[1],avgvel[2]); // DEBUG 01046 } 01047 } 01048 } 01049 01050 // helper, init given array 01051 void ControlParticles::initTimeArray(LbmFloat t, std::vector<ControlParticle> &parts) { 01052 if(mPartSets.size()<1) return; 01053 01054 if(parts.size()!=mPartSets[0].particles.size()) { 01055 //fprintf(stdout,"PRES \n"); 01056 parts.resize(mPartSets[0].particles.size()); 01057 // TODO reset all? 01058 for(size_t j=0; j<parts.size(); j++) { 01059 parts[j].reset(); 01060 } 01061 } 01062 if(parts.size()<1) return; 01063 01064 // debug inits 01065 if(mDebugInit==1) { 01066 // hard coded circle init 01067 for(size_t j=0; j<mPartSets[0].particles.size(); j++) { 01068 ControlParticle p = mPartSets[0].particles[j]; 01069 // remember old 01070 p.density = parts[j].density; 01071 p.densityWeight = parts[j].densityWeight; 01072 p.avgVel = parts[j].avgVel; 01073 p.avgVelAcc = parts[j].avgVelAcc; 01074 p.avgVelWeight = parts[j].avgVelWeight; 01075 LbmVec ppos(0.); { // DEBUG 01076 const float tscale=10.; 01077 const float tprevo = 0.33; 01078 const LbmVec toff(50,50,0); 01079 const LbmVec oscale(30,30,0); 01080 ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0] + toff[0]; 01081 ppos[1] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1] + toff[1]; 01082 ppos[2] = toff[2]; } // DEBUG 01083 p.pos = ppos; 01084 parts[j] = p; 01085 //errMsg("ControlParticle::initTimeArray","j:"<<j<<" p:"<<parts[j].pos ); 01086 } 01087 return; 01088 } 01089 else if(mDebugInit==2) { 01090 // hard coded spiral init 01091 const float tscale=-10.; 01092 const float tprevo = 0.33; 01093 LbmVec toff(50,0,-50); 01094 const LbmVec oscale(20,20,0); 01095 toff[2] += 30. * t +30.; 01096 for(size_t j=0; j<mPartSets[0].particles.size(); j++) { 01097 ControlParticle p = mPartSets[0].particles[j]; 01098 // remember old 01099 p.density = parts[j].density; 01100 p.densityWeight = parts[j].densityWeight; 01101 p.avgVel = parts[j].avgVel; 01102 p.avgVelAcc = parts[j].avgVelAcc; 01103 p.avgVelWeight = parts[j].avgVelWeight; 01104 LbmVec ppos(0.); 01105 ppos[1] = toff[2]; 01106 LbmFloat zscal = (ppos[1]+100.)/200.; 01107 ppos[0] = cos(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[0]*zscal + toff[0]; 01108 ppos[2] = -sin(tscale* t - tprevo*(float)j + M_PI -0.1) * oscale[1]*zscal + toff[1]; 01109 p.pos = ppos; 01110 parts[j] = p; 01111 01112 toff[2] += 0.25; 01113 } 01114 return; 01115 } 01116 01117 // use first set 01118 if((t<=mPartSets[0].time)||(mPartSets.size()==1)) { 01119 //fprintf(stdout,"PINI %f \n", t); 01120 //parts = mPartSets[0].particles; 01121 const int i=0; 01122 for(size_t j=0; j<mPartSets[i].particles.size(); j++) { 01123 ControlParticle p = mPartSets[i].particles[j]; 01124 // remember old 01125 p.density = parts[j].density; 01126 p.densityWeight = parts[j].densityWeight; 01127 p.avgVel = parts[j].avgVel; 01128 p.avgVelAcc = parts[j].avgVelAcc; 01129 p.avgVelWeight = parts[j].avgVelWeight; 01130 parts[j] = p; 01131 } 01132 return; 01133 } 01134 01135 for(int i=0; i<(int)mPartSets.size()-1; i++) { 01136 if((mPartSets[i].time<=t) && (mPartSets[i+1].time>t)) { 01137 LbmFloat d = mPartSets[i+1].time-mPartSets[i].time; 01138 LbmFloat f = (t-mPartSets[i].time)/d; 01139 LbmFloat omf = 1.0f - f; 01140 01141 for(size_t j=0; j<mPartSets[i].particles.size(); j++) { 01142 ControlParticle *src1=&mPartSets[i ].particles[j]; 01143 ControlParticle *src2=&mPartSets[i+1].particles[j]; 01144 ControlParticle &p = parts[j]; 01145 // do linear interpolation 01146 p.pos = src1->pos * omf + src2->pos *f; 01147 p.vel = LbmVec(0.); // reset, calculated later on src1->vel * omf + src2->vel *f; 01148 p.rotaxis = src1->rotaxis * omf + src2->rotaxis *f; 01149 p.influence = src1->influence * omf + src2->influence *f; 01150 p.size = src1->size * omf + src2->size *f; 01151 // dont modify: density, densityWeight 01152 } 01153 } 01154 } 01155 01156 // after last? 01157 if(t>=mPartSets[ mPartSets.size() -1 ].time) { 01158 //parts = mPartSets[ mPartSets.size() -1 ].particles; 01159 const int i= (int)mPartSets.size() -1; 01160 for(size_t j=0; j<mPartSets[i].particles.size(); j++) { 01161 ControlParticle p = mPartSets[i].particles[j]; 01162 // restore 01163 p.density = parts[j].density; 01164 p.densityWeight = parts[j].densityWeight; 01165 p.avgVel = parts[j].avgVel; 01166 p.avgVelAcc = parts[j].avgVelAcc; 01167 p.avgVelWeight = parts[j].avgVelWeight; 01168 parts[j] = p; 01169 } 01170 } 01171 } 01172 01173 01174 01175 01176 // -------------------------------------------------------------------------- 01177 01178 #define DEBUG_MODVEL 0 01179 01180 // recalculate 01181 void ControlParticles::calculateKernelWeight() { 01182 const bool debugKernel = true; 01183 01184 // calculate kernel area with respect to particlesize/cellsize 01185 LbmFloat kernelw = -1.; 01186 LbmFloat kernelnorm = -1.; 01187 LbmFloat krad = (_radiusAtt*0.75); // FIXME use real cone approximation...? 01188 //krad = (_influenceFalloff*1.); 01189 #if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2) 01190 kernelw = CP_PI*krad*krad; 01191 kernelnorm = 1.0 / (_fluidSpacing * _fluidSpacing); 01192 #else // 2D 01193 kernelw = CP_PI*krad*krad*krad* (4./3.); 01194 kernelnorm = 1.0 / (_fluidSpacing * _fluidSpacing * _fluidSpacing); 01195 #endif // MAIN_2D 01196 01197 if(debugKernel) debMsgStd("ControlParticles::calculateKernelWeight",DM_MSG,"kw"<<kernelw<<", norm"<< 01198 kernelnorm<<", w*n="<<(kernelw*kernelnorm)<<", rad"<<krad<<", sp"<<_fluidSpacing<<" ", 7); 01199 LbmFloat kernelws = kernelw*kernelnorm; 01200 _kernelWeight = kernelws; 01201 if(debugKernel) debMsgStd("ControlParticles::calculateKernelWeight",DM_MSG,"influence f="<<_radiusAtt<<" t="<< 01202 _influenceTangential<<" a="<<_influenceAttraction<<" v="<<_influenceVelocity<<" kweight="<<_kernelWeight, 7); 01203 if(_kernelWeight<=0.) { 01204 errMsg("ControlParticles::calculateKernelWeight", "invalid kernel! "<<_kernelWeight<<", resetting"); 01205 _kernelWeight = 1.; 01206 } 01207 } 01208 01209 void 01210 ControlParticles::prepareControl(LbmFloat simtime, LbmFloat dt, ControlParticles *motion) { 01211 debMsgStd("ControlParticle::prepareControl",DM_MSG," simtime="<<simtime<<" dt="<<dt<<" ", 5); 01212 01213 //fprintf(stdout,"PREPARE \n"); 01214 LbmFloat avgdw = 0.; 01215 for(size_t i=0; i<_particles.size(); i++) { 01216 ControlParticle *cp = &_particles[i]; 01217 01218 if(this->getInfluenceAttraction()<0.) { 01219 cp->density= 01220 cp->densityWeight = 1.0; 01221 continue; 01222 } 01223 01224 // normalize by kernel 01225 //cp->densityWeight = (1.0 - (cp->density / _kernelWeight)); // store last 01226 #if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2) 01227 cp->densityWeight = (1.0 - (cp->density / (_kernelWeight*cp->size*cp->size) )); // store last 01228 #else // 2D 01229 cp->densityWeight = (1.0 - (cp->density / (_kernelWeight*cp->size*cp->size*cp->size) )); // store last 01230 #endif // MAIN_2D 01231 01232 if(i<10) debMsgStd("ControlParticle::prepareControl",DM_MSG,"kernelDebug i="<<i<<" densWei="<<cp->densityWeight<<" 1/kw"<<(1.0/_kernelWeight)<<" cpdensity="<<cp->density, 9 ); 01233 if(cp->densityWeight<0.) cp->densityWeight=0.; 01234 if(cp->densityWeight>1.) cp->densityWeight=1.; 01235 01236 avgdw += cp->densityWeight; 01237 // reset for next step 01238 cp->density = 0.; 01239 01240 if(cp->avgVelWeight>0.) { 01241 cp->avgVel = cp->avgVelAcc/cp->avgVelWeight; 01242 cp->avgVelWeight = 0.; 01243 cp->avgVelAcc = LbmVec(0.,0.,0.); 01244 } 01245 } 01246 //if(debugKernel) for(size_t i=0; i<_particles.size(); i++) { ControlParticle *cp = &_particles[i]; fprintf(stdout,"A %f,%f \n",cp->density,cp->densityWeight); } 01247 avgdw /= (LbmFloat)(_particles.size()); 01248 //if(motion) { printf("ControlParticle::kernel: avgdw:%f, kw%f, sp%f \n", avgdw, _kernelWeight, _fluidSpacing); } 01249 01250 //if((simtime>=0.) && (simtime != _currTime)) 01251 initTime(simtime, dt); 01252 01253 if((motion) && (motion->getSize()>0)){ 01254 ControlParticle *motionp = motion->getParticle(0); 01255 //printf("ControlParticle::prepareControl motion: pos[%f,%f,%f] vel[%f,%f,%f] \n", motionp->pos[0], motionp->pos[1], motionp->pos[2], motionp->vel[0], motionp->vel[1], motionp->vel[2] ); 01256 for(size_t i=0; i<_particles.size(); i++) { 01257 ControlParticle *cp = &_particles[i]; 01258 cp->pos = cp->pos + motionp->pos; 01259 cp->vel = cp->vel + motionp->vel; 01260 cp->size = cp->size * motionp->size; 01261 cp->influence = cp->size * motionp->influence; 01262 } 01263 } 01264 01265 // reset to radiusAtt by default 01266 if(_radiusVel==0.) _radiusVel = _radiusAtt; 01267 if(_radiusMinMaxd==0.) _radiusMinMaxd = _radiusAtt; 01268 if(_radiusMaxd==0.) _radiusMaxd = 2.*_radiusAtt; 01269 // has to be radiusVel<radiusAtt<radiusMinMaxd<radiusMaxd 01270 if(_radiusVel>_radiusAtt) _radiusVel = _radiusAtt; 01271 if(_radiusAtt>_radiusMinMaxd) _radiusAtt = _radiusMinMaxd; 01272 if(_radiusMinMaxd>_radiusMaxd) _radiusMinMaxd = _radiusMaxd; 01273 01274 //printf("ControlParticle::radii vel:%f att:%f min:%f max:%f \n", _radiusVel,_radiusAtt,_radiusMinMaxd,_radiusMaxd); 01275 // prepareControl done 01276 } 01277 01278 void ControlParticles::finishControl(std::vector<ControlForces> &forces, LbmFloat iatt, LbmFloat ivel, LbmFloat imaxd) { 01279 01280 //const LbmFloat iatt = this->getInfluenceAttraction() * this->getCurrTimestep(); 01281 //const LbmFloat ivel = this->getInfluenceVelocity(); 01282 //const LbmFloat imaxd = this->getInfluenceMaxdist() * this->getCurrTimestep(); 01283 // prepare for usage 01284 iatt *= this->getCurrTimestep(); 01285 ivel *= 1.; // not necessary! 01286 imaxd *= this->getCurrTimestep(); 01287 01288 // skip when size=0 01289 for(int i=0; i<(int)forces.size(); i++) { 01290 if(DEBUG_MODVEL) fprintf(stdout, "CPFORGF %d , wf:%f,f:%f,%f,%f , v:%f,%f,%f \n",i, forces[i].weightAtt, forces[i].forceAtt[0],forces[i].forceAtt[1],forces[i].forceAtt[2], forces[i].forceVel[0], forces[i].forceVel[1], forces[i].forceVel[2] ); 01291 LbmFloat cfweight = forces[i].weightAtt; // always normalize 01292 if((cfweight!=0.)&&(iatt!=0.)) { 01293 // multiple kernels, normalize - note this does not normalize in d>r/2 region 01294 if(ABS(cfweight)>1.) { cfweight = 1.0/cfweight; } 01295 // multiply iatt afterwards to allow stronger force 01296 cfweight *= iatt; 01297 forces[i].forceAtt *= cfweight; 01298 } else { 01299 forces[i].weightAtt = 0.; 01300 forces[i].forceAtt = LbmVec(0.); 01301 } 01302 01303 if( (cfweight==0.) && (imaxd>0.) && (forces[i].maxDistance>0.) ) { 01304 forces[i].forceMaxd *= imaxd; 01305 } else { 01306 forces[i].maxDistance= 0.; 01307 forces[i].forceMaxd = LbmVec(0.); 01308 } 01309 01310 LbmFloat cvweight = forces[i].weightVel; // always normalize 01311 if(cvweight>0.) { 01312 forces[i].forceVel /= cvweight; 01313 forces[i].compAv /= cvweight; 01314 // now modify cvweight, and write back 01315 // important, cut at 1 - otherwise strong vel. influences... 01316 if(cvweight>1.) { cvweight = 1.; } 01317 // thus cvweight is in the range of 0..influenceVelocity, currently not normalized by numCParts 01318 cvweight *= ivel; 01319 if(cvweight<0.) cvweight=0.; if(cvweight>1.) cvweight=1.; 01320 // LBM, FIXME todo use relaxation factor 01321 //pvel = (cvel*0.5 * cvweight) + (pvel * (1.0-cvweight)); 01322 forces[i].weightVel = cvweight; 01323 01324 //errMsg("COMPAV","i"<<i<<" compav"<<forces[i].compAv<<" forcevel"<<forces[i].forceVel<<" "); 01325 } else { 01326 forces[i].weightVel = 0.; 01327 if(forces[i].maxDistance==0.) forces[i].forceVel = LbmVec(0.); 01328 forces[i].compAvWeight = 0.; 01329 forces[i].compAv = LbmVec(0.); 01330 } 01331 if(DEBUG_MODVEL) fprintf(stdout, "CPFINIF %d , wf:%f,f:%f,%f,%f , v:%f,%f,%f \n",i, forces[i].weightAtt, forces[i].forceAtt[0],forces[i].forceAtt[1],forces[i].forceAtt[2], forces[i].forceVel[0],forces[i].forceVel[1],forces[i].forceVel[2] ); 01332 } 01333 01334 // unused... 01335 if(DEBUG_MODVEL) fprintf(stdout,"MFC iatt:%f,%f ivel:%f,%f ifmd:%f,%f \n", iatt,_radiusAtt, ivel,_radiusVel, imaxd, _radiusMaxd); 01336 //for(size_t i=0; i<_particles.size(); i++) { ControlParticle *cp = &_particles[i]; fprintf(stdout," %f,%f,%f ",cp->density,cp->densityWeight, (1.0 - (12.0*cp->densityWeight))); } 01337 //fprintf(stdout,"\n\nCP DONE \n\n\n"); 01338 } 01339 01340 01341 // -------------------------------------------------------------------------- 01342 // calculate forces at given position, and modify velocity 01343 // according to timestep 01344 void ControlParticles::calculateCpInfluenceOpt(ControlParticle *cp, LbmVec fluidpos, LbmVec fluidvel, ControlForces *force, LbmFloat fillFactor) { 01345 // dont reset, only add... 01346 // test distance, simple squared distance reject 01347 const LbmFloat cpfo = _radiusAtt*cp->size; 01348 01349 LbmVec posDelta; 01350 if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f bef fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]); 01351 posDelta = cp->pos - fluidpos; 01352 #if LBMDIM==2 && (CP_PROJECT2D==1) 01353 posDelta[2] = 0.; // project to xy plane, z-velocity should already be gone... 01354 #endif 01355 01356 const LbmFloat distsqr = posDelta[0]*posDelta[0]+posDelta[1]*posDelta[1]+posDelta[2]*posDelta[2]; 01357 if(DEBUG_MODVEL) fprintf(stdout, " Pd at %f,%f,%f d%f \n",posDelta[0],posDelta[1],posDelta[2], distsqr); 01358 // cut at influence=0.5 , scaling not really makes sense 01359 if(cpfo*cpfo < distsqr) { 01360 /*if(cp->influence>0.5) { 01361 if(force->weightAtt == 0.) { 01362 if(force->maxDistance*force->maxDistance > distsqr) { 01363 const LbmFloat dis = sqrtf((float)distsqr); 01364 const LbmFloat sc = dis-cpfo; 01365 force->maxDistance = dis; 01366 force->forceMaxd = (posDelta)*(sc/dis); 01367 } 01368 } } */ 01369 return; 01370 } 01371 force->weightAtt += 1e-6; // for distance 01372 force->maxDistance = 0.; // necessary for SPH? 01373 01374 const LbmFloat pdistance = MAGNITUDE(posDelta); 01375 LbmFloat pdistinv = 0.; 01376 if(ABS(pdistance)>0.) pdistinv = 1./pdistance; 01377 posDelta *= pdistinv; 01378 01379 LbmFloat falloffAtt = 0.; //CPKernel::kernel(cpfo * 1.0, pdistance); 01380 const LbmFloat qac = pdistance / cpfo ; 01381 if (qac < 1.0){ // return 0.; 01382 if(qac < 0.5) falloffAtt = 1.0f; 01383 else falloffAtt = (1.0f - qac) * 2.0f; 01384 } 01385 01386 // vorticity force: 01387 // - //LbmVec forceVort; 01388 // - //CROSS(forceVort, posDelta, cp->rotaxis); 01389 // - //NORMALIZE(forceVort); 01390 // - if(falloffAtt>1.0) falloffAtt=1.0; 01391 01392 #if (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2) 01393 // fillFactor *= 2.0 *0.75 * pdistance; // 2d>3d sampling 01394 #endif // (CP_PROJECT2D==1) && (defined(MAIN_2D) || LBMDIM==2) 01395 01396 LbmFloat signum = getInfluenceAttraction() > 0.0 ? 1.0 : -1.0; 01397 cp->density += falloffAtt * fillFactor; 01398 force->forceAtt += posDelta *cp->densityWeight *cp->influence *signum; 01399 force->weightAtt += falloffAtt*cp->densityWeight *cp->influence; 01400 01401 LbmFloat falloffVel = 0.; //CPKernel::kernel(cpfo * 1.0, pdistance); 01402 const LbmFloat cpfv = _radiusVel*cp->size; 01403 if(cpfv*cpfv < distsqr) { return; } 01404 const LbmFloat qvc = pdistance / cpfo ; 01405 //if (qvc < 1.0){ 01406 //if(qvc < 0.5) falloffVel = 1.0f; 01407 //else falloffVel = (1.0f - qvc) * 2.0f; 01408 //} 01409 falloffVel = 1.-qvc; 01410 01411 LbmFloat pvWeight; // = (1.0-cp->densityWeight) * _currTimestep * falloffVel; 01412 pvWeight = falloffVel *cp->influence; // std, without density influence 01413 //pvWeight *= (1.0-cp->densityWeight); // use inverse density weight 01414 //pvWeight *= cp->densityWeight; // test, use density weight 01415 LbmVec modvel(0.); 01416 modvel += cp->vel * pvWeight; 01417 //pvWeight = 1.; modvel = partVel; // DEBUG!? 01418 01419 if(pvWeight>0.) { 01420 force->forceVel += modvel; 01421 force->weightVel += pvWeight; 01422 01423 cp->avgVelWeight += falloffVel; 01424 cp->avgVel += fluidvel; 01425 } 01426 if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f aft fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]); 01427 return; 01428 } 01429 01430 void ControlParticles::calculateMaxdForce(ControlParticle *cp, LbmVec fluidpos, ControlForces *force) { 01431 if(force->weightAtt != 0.) return; // maxd force off 01432 if(cp->influence <= 0.5) return; // ignore 01433 01434 LbmVec posDelta; 01435 //if(DEBUG_MODVEL) fprintf(stdout, "CP at %f,%f,%f bef fw:%f, f:%f,%f,%f , vw:%f, v:%f,%f,%f \n",fluidpos[0],fluidpos[1],fluidpos[2], force->weightAtt, force->forceAtt[0], force->forceAtt[1], force->forceAtt[2], force->weightVel, force->forceVel[0], force->forceVel[1], force->forceVel[2]); 01436 posDelta = cp->pos - fluidpos; 01437 #if LBMDIM==2 && (CP_PROJECT2D==1) 01438 posDelta[2] = 0.; // project to xy plane, z-velocity should already be gone... 01439 #endif 01440 01441 // dont reset, only add... 01442 // test distance, simple squared distance reject 01443 const LbmFloat distsqr = posDelta[0]*posDelta[0]+posDelta[1]*posDelta[1]+posDelta[2]*posDelta[2]; 01444 01445 // closer cp found 01446 if(force->maxDistance*force->maxDistance < distsqr) return; 01447 01448 const LbmFloat dmin = _radiusMinMaxd*cp->size; 01449 if(distsqr<dmin*dmin) return; // inside min 01450 const LbmFloat dmax = _radiusMaxd*cp->size; 01451 if(distsqr>dmax*dmax) return; // outside 01452 01453 01454 if(DEBUG_MODVEL) fprintf(stdout, " Pd at %f,%f,%f d%f \n",posDelta[0],posDelta[1],posDelta[2], distsqr); 01455 // cut at influence=0.5 , scaling not really makes sense 01456 const LbmFloat dis = sqrtf((float)distsqr); 01457 //const LbmFloat sc = dis - dmin; 01458 const LbmFloat sc = (dis-dmin)/(dmax-dmin); // scale from 0-1 01459 force->maxDistance = dis; 01460 force->forceMaxd = (posDelta/dis) * sc; 01461 //debug errMsg("calculateMaxdForce","pos"<<fluidpos<<" dis"<<dis<<" sc"<<sc<<" dmin"<<dmin<<" maxd"<< force->maxDistance <<" fmd"<<force->forceMaxd ); 01462 return; 01463 } 01464