Blender  V2.59
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