Blender V2.61 - r43446

controlparticles.cpp

Go to the documentation of this file.
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