rebranch from 2.5
[blender.git] / intern / elbeem / intern / solver_control.cpp
1 /******************************************************************************
2  *
3  * El'Beem - the visual lattice boltzmann freesurface simulator
4  * All code distributed as part of El'Beem is covered by the version 2 of the 
5  * GNU General Public License. See the file COPYING for details.  
6  *
7  * Copyright 2003-2008 Nils Thuerey 
8  *
9  * control extensions
10  *
11  *****************************************************************************/
12 #include "solver_class.h"
13 #include "solver_relax.h"
14 #include "particletracer.h"
15
16 #include "solver_control.h"
17
18 #include "controlparticles.h"
19
20 #include "elbeem.h"
21
22 #include "ntl_geometrymodel.h"
23
24 /******************************************************************************
25  * LbmControlData control set
26  *****************************************************************************/
27
28 LbmControlSet::LbmControlSet() :
29         mCparts(NULL), mCpmotion(NULL), mContrPartFile(""), mCpmotionFile(""),
30         mcForceAtt(0.), mcForceVel(0.), mcForceMaxd(0.), 
31         mcRadiusAtt(0.), mcRadiusVel(0.), mcRadiusMind(0.), mcRadiusMaxd(0.), 
32         mcCpScale(1.), mcCpOffset(0.)
33 {
34 }
35 LbmControlSet::~LbmControlSet() {
36         if(mCparts) delete mCparts;
37         if(mCpmotion) delete mCpmotion;
38 }
39 void LbmControlSet::initCparts() {
40         mCparts = new ControlParticles();
41         mCpmotion = new ControlParticles();
42 }
43
44
45
46 /******************************************************************************
47  * LbmControlData control
48  *****************************************************************************/
49
50 LbmControlData::LbmControlData() : 
51         mSetForceStrength(0.),
52         mCons(), 
53         mCpUpdateInterval(8), // DG: was 16 --> causes problems (big sphere after some time), unstable
54         mCpOutfile(""), 
55         mCpForces(), mCpKernel(), mMdKernel(),
56         mDiffVelCon(1.),
57         mDebugCpscale(0.), 
58         mDebugVelScale(0.), 
59         mDebugCompavScale(0.), 
60         mDebugAttScale(0.), 
61         mDebugMaxdScale(0.),
62         mDebugAvgVelScale(0.)
63 {
64 }
65
66 LbmControlData::~LbmControlData() 
67 {
68         while (!mCons.empty()) {
69                 delete mCons.back();  mCons.pop_back();
70         }
71 }
72
73
74 void LbmControlData::parseControldataAttrList(AttributeList *attr) {
75         // controlpart vars
76         mSetForceStrength = attr->readFloat("tforcestrength", mSetForceStrength,"LbmControlData", "mSetForceStrength", false);
77         //errMsg("tforcestrength set to "," "<<mSetForceStrength);
78         mCpUpdateInterval = attr->readInt("controlparticle_updateinterval", mCpUpdateInterval,"LbmControlData","mCpUpdateInterval", false);
79         // tracer output file
80         mCpOutfile = attr->readString("controlparticle_outfile",mCpOutfile,"LbmControlData","mCpOutfile", false);
81         if(getenv("ELBEEM_CPOUTFILE")) {
82                 string outfile(getenv("ELBEEM_CPOUTFILE"));
83                 mCpOutfile = outfile;
84                 debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPOUTFILE to set mCpOutfile to "<<outfile<<","<<mCpOutfile,7);
85         }
86
87         for(int cpii=0; cpii<10; cpii++) {
88                 string suffix("");
89                 //if(cpii>0)
90                 {  suffix = string("0"); suffix[0]+=cpii; }
91                 LbmControlSet *cset;
92                 cset = new LbmControlSet();
93                 cset->initCparts();
94
95                 cset->mContrPartFile = attr->readString("controlparticle"+suffix+"_file",cset->mContrPartFile,"LbmControlData","cset->mContrPartFile", false);
96                 if((cpii==0) && (getenv("ELBEEM_CPINFILE")) ) {
97                         string infile(getenv("ELBEEM_CPINFILE"));
98                         cset->mContrPartFile = infile;
99                         debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPINFILE to set mContrPartFile to "<<infile<<","<<cset->mContrPartFile,7);
100                 }
101
102                 LbmFloat cpvort=0.;
103                 cset->mcRadiusAtt =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusatt", 0., "LbmControlData","mcRadiusAtt" );
104                 cset->mcRadiusVel =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" );
105                 cset->mcRadiusVel =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" );
106                 cset->mCparts->setRadiusAtt(cset->mcRadiusAtt.get(0.));
107                 cset->mCparts->setRadiusVel(cset->mcRadiusVel.get(0.));
108
109                 // WARNING currently only for first set
110                 //if(cpii==0) {
111                 cset->mcForceAtt  =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_attraction", 0. , "LbmControlData","cset->mcForceAtt", false);
112                 cset->mcForceVel  =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_velocity",   0. , "LbmControlData","mcForceVel", false);
113                 cset->mcForceMaxd =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_maxdist",    0. , "LbmControlData","mcForceMaxd", false);
114                 cset->mCparts->setInfluenceAttraction(cset->mcForceAtt.get(0.) );
115                 // warning - stores temprorarily, value converted to dt dep. factor
116                 cset->mCparts->setInfluenceVelocity(cset->mcForceVel.get(0.) , 0.01 ); // dummy dt
117                 cset->mCparts->setInfluenceMaxdist(cset->mcForceMaxd.get(0.) );
118                 cpvort =  attr->readFloat("controlparticle"+suffix+"_vorticity",   cpvort, "LbmControlData","cpvort", false);
119                 cset->mCparts->setInfluenceTangential(cpvort);
120                         
121                 cset->mcRadiusMind =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmin", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMind", false);
122                 cset->mcRadiusMaxd =  attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmax", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMaxd", false);
123                 cset->mCparts->setRadiusMinMaxd(cset->mcRadiusMind.get(0.));
124                 cset->mCparts->setRadiusMaxd(cset->mcRadiusMaxd.get(0.));
125                 //}
126
127                 // now local...
128                 //LbmVec cpOffset(0.), cpScale(1.);
129                 LbmFloat cpTimescale = 1.;
130                 string cpMirroring("");
131
132                 //cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false);
133                 //cset->mcCpScale =  attr->readChannelVec3f("controlparticle"+suffix+"_scale",  ntlVec3f(1.), "LbmControlData","mcCpScale", false);
134                 cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false);
135                 cset->mcCpScale =  attr->readChannelVec3f("controlparticle"+suffix+"_scale",  ntlVec3f(1.), "LbmControlData","mcCpScale", false);
136                 cpTimescale =  attr->readFloat("controlparticle"+suffix+"_timescale",  cpTimescale, "LbmControlData","cpTimescale", false);
137                 cpMirroring =  attr->readString("controlparticle"+suffix+"_mirror",  cpMirroring, "LbmControlData","cpMirroring", false);
138
139                 LbmFloat cpsWidth = cset->mCparts->getCPSWith();
140                 cpsWidth =  attr->readFloat("controlparticle"+suffix+"_cpswidth",  cpsWidth, "LbmControlData","cpsWidth", false);
141                 LbmFloat cpsDt = cset->mCparts->getCPSTimestep();
142                 cpsDt =  attr->readFloat("controlparticle"+suffix+"_cpstimestep",  cpsDt, "LbmControlData","cpsDt", false);
143                 LbmFloat cpsTstart = cset->mCparts->getCPSTimeStart();
144                 cpsTstart =  attr->readFloat("controlparticle"+suffix+"_cpststart",  cpsTstart, "LbmControlData","cpsTstart", false);
145                 LbmFloat cpsTend = cset->mCparts->getCPSTimeEnd();
146                 cpsTend =  attr->readFloat("controlparticle"+suffix+"_cpstend",  cpsTend, "LbmControlData","cpsTend", false);
147                 LbmFloat cpsMvmfac = cset->mCparts->getCPSMvmWeightFac();
148                 cpsMvmfac =  attr->readFloat("controlparticle"+suffix+"_cpsmvmfac",  cpsMvmfac, "LbmControlData","cpsMvmfac", false);
149                 cset->mCparts->setCPSWith(cpsWidth);
150                 cset->mCparts->setCPSTimestep(cpsDt);
151                 cset->mCparts->setCPSTimeStart(cpsTstart);
152                 cset->mCparts->setCPSTimeEnd(cpsTend);
153                 cset->mCparts->setCPSMvmWeightFac(cpsMvmfac);
154
155                 cset->mCparts->setOffset( vec2L(cset->mcCpOffset.get(0.)) );
156                 cset->mCparts->setScale( vec2L(cset->mcCpScale.get(0.)) );
157                 cset->mCparts->setInitTimeScale( cpTimescale );
158                 cset->mCparts->setInitMirror( cpMirroring );
159
160                 int mDebugInit = 0;
161                 mDebugInit = attr->readInt("controlparticle"+suffix+"_debuginit", mDebugInit,"LbmControlData","mDebugInit", false);
162                 cset->mCparts->setDebugInit(mDebugInit);
163
164                 // motion particle settings
165                 LbmVec mcpOffset(0.), mcpScale(1.);
166                 LbmFloat mcpTimescale = 1.;
167                 string mcpMirroring("");
168
169                 cset->mCpmotionFile = attr->readString("cpmotion"+suffix+"_file",cset->mCpmotionFile,"LbmControlData","mCpmotionFile", false);
170                 mcpTimescale =  attr->readFloat("cpmotion"+suffix+"_timescale",  mcpTimescale, "LbmControlData","mcpTimescale", false);
171                 mcpMirroring =  attr->readString("cpmotion"+suffix+"_mirror",  mcpMirroring, "LbmControlData","mcpMirroring", false);
172                 mcpOffset = vec2L( attr->readVec3d("cpmotion"+suffix+"_offset", vec2P(mcpOffset),"LbmControlData","cpOffset", false) );
173                 mcpScale =  vec2L( attr->readVec3d("cpmotion"+suffix+"_scale",  vec2P(mcpScale), "LbmControlData","cpScale", false) );
174
175                 cset->mCpmotion->setOffset( vec2L(mcpOffset) );
176                 cset->mCpmotion->setScale( vec2L(mcpScale) );
177                 cset->mCpmotion->setInitTimeScale( mcpTimescale );
178                 cset->mCpmotion->setInitMirror( mcpMirroring );
179
180                 if(cset->mContrPartFile.length()>1) {
181                         errMsg("LbmControlData","Using control particle set "<<cpii<<" file:"<<cset->mContrPartFile<<" cpmfile:"<<cset->mCpmotionFile<<" mirr:'"<<cset->mCpmotion->getInitMirror()<<"' " );
182                         mCons.push_back( cset );
183                 } else {
184                         delete cset;
185                 }
186         }
187
188         // debug, testing - make sure theres at least an empty set
189         if(mCons.size()<1) {
190                 mCons.push_back( new LbmControlSet() );
191                 mCons[0]->initCparts();
192         }
193
194         // take from first set
195         for(int cpii=1; cpii<(int)mCons.size(); cpii++) {
196                 mCons[cpii]->mCparts->setRadiusMinMaxd( mCons[0]->mCparts->getRadiusMinMaxd() );
197                 mCons[cpii]->mCparts->setRadiusMaxd(    mCons[0]->mCparts->getRadiusMaxd() );
198                 mCons[cpii]->mCparts->setInfluenceAttraction( mCons[0]->mCparts->getInfluenceAttraction() );
199                 mCons[cpii]->mCparts->setInfluenceTangential( mCons[0]->mCparts->getInfluenceTangential() );
200                 mCons[cpii]->mCparts->setInfluenceVelocity( mCons[0]->mCparts->getInfluenceVelocity() , 0.01 ); // dummy dt
201                 mCons[cpii]->mCparts->setInfluenceMaxdist( mCons[0]->mCparts->getInfluenceMaxdist() );
202         }
203         
204         // invert for usage in relax macro
205         mDiffVelCon =  1.-attr->readFloat("cpdiffvelcon",  mDiffVelCon, "LbmControlData","mDiffVelCon", false);
206
207         mDebugCpscale     =  attr->readFloat("cpdebug_cpscale",  mDebugCpscale, "LbmControlData","mDebugCpscale", false);
208         mDebugMaxdScale   =  attr->readFloat("cpdebug_maxdscale",  mDebugMaxdScale, "LbmControlData","mDebugMaxdScale", false);
209         mDebugAttScale    =  attr->readFloat("cpdebug_attscale",  mDebugAttScale, "LbmControlData","mDebugAttScale", false);
210         mDebugVelScale    =  attr->readFloat("cpdebug_velscale",  mDebugVelScale, "LbmControlData","mDebugVelScale", false);
211         mDebugCompavScale =  attr->readFloat("cpdebug_compavscale",  mDebugCompavScale, "LbmControlData","mDebugCompavScale", false);
212         mDebugAvgVelScale =  attr->readFloat("cpdebug_avgvelsc",  mDebugAvgVelScale, "LbmControlData","mDebugAvgVelScale", false);
213 }
214
215
216 void 
217 LbmFsgrSolver::initCpdata()
218 {
219         // enable for cps via env. vars
220         //if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){ mUseTestdata=1; }
221
222         
223         // manually switch on! if this is zero, nothing is done...
224         mpControl->mSetForceStrength = this->mTForceStrength = 1.;
225         mpControl->mCons.clear();
226         
227         // init all control fluid objects
228         int numobjs = (int)(mpGiObjects->size());
229         for(int o=0; o<numobjs; o++) {
230                 ntlGeometryObjModel *obj = (ntlGeometryObjModel *)(*mpGiObjects)[o];
231                 if(obj->getGeoInitType() & FGI_CONTROL) {
232                         // add new control set per object
233                         LbmControlSet *cset;
234
235                         cset = new LbmControlSet();
236                         cset->initCparts();
237         
238                         // dont load any file
239                         cset->mContrPartFile = string("");
240
241                         cset->mcForceAtt = obj->getCpsAttrFStr();
242                         cset->mcRadiusAtt = obj->getCpsAttrFRad();
243                         cset->mcForceVel = obj->getCpsVelFStr();
244                         cset->mcRadiusVel = obj->getCpsVelFRad();
245
246                         cset->mCparts->setCPSTimeStart(obj->getCpsTimeStart());
247                         cset->mCparts->setCPSTimeEnd(obj->getCpsTimeEnd());
248                         
249                         if(obj->getCpsQuality() > LBM_EPSILON)
250                                 cset->mCparts->setCPSWith(1.0 / obj->getCpsQuality());
251                         
252                         // this value can be left at 0.5:
253                         cset->mCparts->setCPSMvmWeightFac(0.5);
254
255                         mpControl->mCons.push_back( cset );
256                         mpControl->mCons[mpControl->mCons.size()-1]->mCparts->initFromObject(obj);
257                 }
258         }
259         
260         // NT blender integration manual test setup
261         if(0) {
262                 // manually switch on! if this is zero, nothing is done...
263                 mpControl->mSetForceStrength = this->mTForceStrength = 1.;
264                 mpControl->mCons.clear();
265
266                 // add new set
267                 LbmControlSet *cset;
268
269                 cset = new LbmControlSet();
270                 cset->initCparts();
271                 // dont load any file
272                 cset->mContrPartFile = string("");
273
274                 // set radii for attraction & velocity forces
275                 // set strength of the forces
276                 // don't set directly! but use channels: 
277                 // mcForceAtt, mcForceVel, mcForceMaxd, mcRadiusAtt, mcRadiusVel, mcRadiusMind, mcRadiusMaxd etc.
278
279                 // wrong: cset->mCparts->setInfluenceAttraction(1.15); cset->mCparts->setRadiusAtt(1.5);
280                 // right, e.g., to init some constant values:
281                 cset->mcForceAtt = AnimChannel<float>(0.2);
282                 cset->mcRadiusAtt = AnimChannel<float>(0.75);
283                 cset->mcForceVel = AnimChannel<float>(0.2);
284                 cset->mcRadiusVel = AnimChannel<float>(0.75);
285
286                 // this value can be left at 0.5:
287                 cset->mCparts->setCPSMvmWeightFac(0.5);
288
289                 mpControl->mCons.push_back( cset );
290
291                 // instead of reading from file (cset->mContrPartFile), manually init some particles
292                 mpControl->mCons[0]->mCparts->initBlenderTest();
293
294                 // other values that might be interesting to change:
295                 //cset->mCparts->setCPSTimestep(0.02);
296                 //cset->mCparts->setCPSTimeStart(0.);
297                 //cset->mCparts->setCPSTimeEnd(1.); 
298
299                 //mpControl->mDiffVelCon = 1.; // more rigid velocity control, 0 (default) allows more turbulence
300         }
301
302         // control particle -------------------------------------------------------------------------------------
303
304         // init cppf stage, use set 0!
305         if(mCppfStage>0) {
306                 if(mpControl->mCpOutfile.length()<1) mpControl->mCpOutfile = string("cpout"); // use getOutFilename !?
307                 char strbuf[100];
308                 const char *cpFormat = "_d%dcppf%d";
309
310                 // initial coarse stage, no input
311                 if(mCppfStage==1) {
312                         mpControl->mCons[0]->mContrPartFile = "";
313                 } else {
314                         // read from prev stage
315                         snprintf(strbuf,100, cpFormat  ,LBMDIM,mCppfStage-1);
316                         mpControl->mCons[0]->mContrPartFile = mpControl->mCpOutfile;
317                         mpControl->mCons[0]->mContrPartFile += strbuf;
318                         mpControl->mCons[0]->mContrPartFile += ".cpart2";
319                 }
320
321                 snprintf(strbuf,100, cpFormat  ,LBMDIM,mCppfStage);
322                 mpControl->mCpOutfile += strbuf;
323         } // */
324         
325         for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
326                 ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
327                 ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
328
329                 // now set with real dt
330                 cparts->setInfluenceVelocity( mpControl->mCons[cpssi]->mcForceVel.get(0.), mLevel[mMaxRefine].timestep);
331                 cparts->setCharLength( mLevel[mMaxRefine].nodeSize );
332                 cparts->setCharLength( mLevel[mMaxRefine].nodeSize );
333                 errMsg("LbmControlData","CppfStage "<<mCppfStage<<" in:"<<mpControl->mCons[cpssi]->mContrPartFile<<
334                                 " out:"<<mpControl->mCpOutfile<<" cl:"<< cparts->getCharLength() );
335
336                 // control particle test init
337                 if(mpControl->mCons[cpssi]->mCpmotionFile.length()>=1) cpmotion->initFromTextFile(mpControl->mCons[cpssi]->mCpmotionFile);
338                 // not really necessary...
339                 //? cparts->setFluidSpacing( mLevel[mMaxRefine].nodeSize        ); // use grid coords!?
340                 //? cparts->calculateKernelWeight();
341                 //? debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - motion inited: "<<cparts->getSize() ,10);
342
343                 // ensure both are on for env. var settings
344                 // when no particles, but outfile enabled, initialize
345                 const int lev = mMaxRefine;
346                 if((mpParticles) && (mpControl->mCpOutfile.length()>=1) && (cpssi==0)) {
347                         // check if auto num
348                         if( (mpParticles->getNumInitialParticles()<=1) && 
349                                         (mpParticles->getNumParticles()<=1) ) { // initParticles done afterwards anyway
350                                 int tracers = 0;
351                                 const int workSet = mLevel[lev].setCurr;
352                                 FSGR_FORIJK_BOUNDS(lev) { 
353                                         if(RFLAG(lev,i,j,k, workSet)&(CFFluid)) tracers++;
354                                 }
355                                 if(LBMDIM==3) tracers /= 8;
356                                 else          tracers /= 4;
357                                 mpParticles->setNumInitialParticles(tracers);
358                                 mpParticles->setDumpTextFile(mpControl->mCpOutfile);
359                                 debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - set tracers #"<<tracers<<", actual #"<<mpParticles->getNumParticles() ,10);
360                         }
361                         if(mpParticles->getDumpTextInterval()<=0.) {
362                                 mpParticles->setDumpTextInterval(mLevel[lev].timestep * mLevel[lev].lSizex);
363                                 debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - dump delta t not set, using dti="<< mpParticles->getDumpTextInterval()<<", sim dt="<<mLevel[lev].timestep, 5 );
364                         }
365                         mpParticles->setDumpParts(true); // DEBUG? also dump as particle system
366                 }
367
368                 if(mpControl->mCons[cpssi]->mContrPartFile.length()>=1) cparts->initFromTextFile(mpControl->mCons[cpssi]->mContrPartFile);
369                 cparts->setFluidSpacing( mLevel[lev].nodeSize   ); // use grid coords!?
370                 cparts->calculateKernelWeight();
371                 debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles mCons"<<cpssi<<" - inited, parts:"<<cparts->getTotalSize()<<","<<cparts->getSize()<<" dt:"<<mpParam->getTimestep()<<" control time:"<<cparts->getControlTimStart()<<" to "<<cparts->getControlTimEnd() ,10);
372         } // cpssi
373
374         if(getenv("ELBEEM_CPINFILE")) {
375                 this->mTForceStrength = 1.0;
376         }
377         this->mTForceStrength = mpControl->mSetForceStrength;
378         if(mpControl->mCpOutfile.length()>=1) mpParticles->setDumpTextFile(mpControl->mCpOutfile);
379
380         // control particle  init end -------------------------------------------------------------------------------------
381
382         // make sure equiv to solver init
383         if(this->mTForceStrength>0.) { \
384                 mpControl->mCpForces.resize( mMaxRefine+1 );
385                 for(int lev = 0; lev<=mMaxRefine; lev++) {
386                         LONGINT rcellSize = (mLevel[lev].lSizex*mLevel[lev].lSizey*mLevel[lev].lSizez);
387                         debMsgStd("LbmFsgrSolver::initControl",DM_MSG,"mCpForces init, lev="<<lev<<" rcs:"<<(int)(rcellSize+4)<<","<<(rcellSize*sizeof(ControlForces)/(1024*1024)), 9 );
388                         mpControl->mCpForces[lev].resize( (int)(rcellSize+4) );
389                         //for(int i=0 ;i<rcellSize; i++) mpControl->mCpForces.push_back( ControlForces() );
390                         for(int i=0 ;i<rcellSize; i++) mpControl->mCpForces[lev][i].resetForces();
391                 }
392         } // on?
393
394         debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles #mCons "<<mpControl->mCons.size()<<" done", 6);
395 }
396
397
398 #define CPODEBUG 0
399 //define CPINTER ((int)(mpControl->mCpUpdateInterval))
400
401 #define KERN(x,y,z)    mpControl->mCpKernel[ (((z)*cpkarWidth + (y))*cpkarWidth + (x)) ]
402 #define MDKERN(x,y,z)  mpControl->mMdKernel[ (((z)*mdkarWidth + (y))*mdkarWidth + (x)) ]
403
404 #define BOUNDCHECK(x,low,high)  ( ((x)<low) ? low : (((x)>high) ? high : (x) )  )
405 #define BOUNDSKIP(x,low,high)  ( ((x)<low) || ((x)>high) )
406
407 void 
408 LbmFsgrSolver::handleCpdata()
409 {
410         myTime_t cpstart = getTime();
411         int cpChecks=0;
412         int cpInfs=0;
413         //debMsgStd("ControlData::handleCpdata",DM_MSG,"called... "<<this->mTForceStrength,1);
414
415         // add cp influence
416   if((true) && (this->mTForceStrength>0.)) {
417                 // ok continue...
418         } // on off
419         else {
420                 return;
421         }
422         
423         // check if we have control objects
424         if(mpControl->mCons.size()==0)
425                 return;
426         
427         if((mpControl->mCpUpdateInterval<1) || (this->mStepCnt%mpControl->mCpUpdateInterval==0)) {
428                 // do full reinit later on... 
429         }
430         else if(this->mStepCnt>mpControl->mCpUpdateInterval) {
431                 // only reinit new cells
432                 // TODO !? remove loop dependance!?
433 #define NOFORCEENTRY(lev, i,j,k) (LBMGET_FORCE(lev, i,j,k).maxDistance==CPF_MAXDINIT) 
434                 // interpolate missing
435                 for(int lev=0; lev<=mMaxRefine; lev++) {
436                 FSGR_FORIJK_BOUNDS(lev) { 
437                         if( (RFLAG(lev,i,j,k, mLevel[lev].setCurr)) & (CFFluid|CFInter) )  
438                         //if( (RFLAG(lev,i,j,k, mLevel[lev].setCurr)) & (CFInter) )  
439                         //if(0)
440                         { // only check new inter? RFLAG?check
441                                 if(NOFORCEENTRY(lev, i,j,k)) {
442                                         //errMsg("CP","FE_MISSING at "<<PRINT_IJK<<" f"<<LBMGET_FORCE(lev, i,j,k).weightAtt<<" md"<<LBMGET_FORCE(lev, i,j,k).maxDistance );
443
444                                         LbmFloat nbs=0.;
445                                         ControlForces vals;
446                                         vals.resetForces(); vals.maxDistance = 0.;
447                                         for(int l=1; l<this->cDirNum; l++) { 
448                                                 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l];
449                                                 //errMsg("CP","FE_MISSING check "<<PRINT_VEC(ni,nj,nk)<<" f"<<LBMGET_FORCE(lev, ni,nj,nk).weightAtt<<" md"<<LBMGET_FORCE(lev, ni,nj,nk).maxDistance );
450                                                 if(!NOFORCEENTRY(lev, ni,nj,nk)) {
451                                                         //? vals.weightAtt   += LBMGET_FORCE(lev, ni,nj,nk).weightAtt;
452                                                         //? vals.forceAtt    += LBMGET_FORCE(lev, ni,nj,nk).forceAtt;
453                                                         vals.maxDistance += LBMGET_FORCE(lev, ni,nj,nk).maxDistance;
454                                                         vals.forceMaxd   += LBMGET_FORCE(lev, ni,nj,nk).forceMaxd;
455                                                         vals.weightVel   += LBMGET_FORCE(lev, ni,nj,nk).weightVel;
456                                                         vals.forceVel    += LBMGET_FORCE(lev, ni,nj,nk).forceVel; 
457                                                         // ignore att/compAv/avgVel here for now
458                                                         nbs += 1.;
459                                                 }
460                                         }
461                                         if(nbs>0.) {
462                                                 nbs = 1./nbs;
463                                                 //? LBMGET_FORCE(lev, i,j,k).weightAtt   =      vals.weightAtt*nbs;
464                                                 //? LBMGET_FORCE(lev, i,j,k).forceAtt    = vals.forceAtt*nbs;
465                                                 LBMGET_FORCE(lev, i,j,k).maxDistance = vals.maxDistance*nbs;
466                                                 LBMGET_FORCE(lev, i,j,k).forceMaxd   =  vals.forceMaxd*nbs;
467                                                 LBMGET_FORCE(lev, i,j,k).weightVel   =  vals.weightVel*nbs;
468                                                 LBMGET_FORCE(lev, i,j,k).forceVel    = vals.forceVel*nbs;
469                                         }
470                                                 /*ControlForces *ff = &LBMGET_FORCE(lev, i,j,k);  // DEBUG
471                                                 errMsg("CP","FE_MISSING rec at "<<PRINT_IJK // DEBUG
472                                                                 <<" w:"<<ff->weightAtt<<" wa:" <<PRINT_VEC( ff->forceAtt[0],ff->forceAtt[1],ff->forceAtt[2] )  
473                                                                 <<" v:"<<ff->weightVel<<" wv:" <<PRINT_VEC( ff->forceVel[0],ff->forceVel[1],ff->forceVel[2] )  
474                                                                 <<" v:"<<ff->maxDistance<<" wv:" <<PRINT_VEC( ff->forceMaxd[0],ff->forceMaxd[1],ff->forceMaxd[2] )  ); // DEBUG */
475                                         // else errMsg("CP","FE_MISSING rec at "<<PRINT_IJK<<" failed!"); // DEBUG
476                                         
477                                 }
478                         }
479                 }} // ijk, lev
480
481                 // mStepCnt > mpControl->mCpUpdateInterval
482                 return;
483         } else {
484                 // nothing to do ...
485                 return;
486         }
487
488         // reset
489         for(int lev=0; lev<=mMaxRefine; lev++) {
490                 FSGR_FORIJK_BOUNDS(lev) { LBMGET_FORCE(lev,i,j,k).resetForces(); }
491         }
492         // do setup for coarsest level
493         const int coarseLev = 0;
494         const int fineLev = mMaxRefine;
495
496         // init for current time
497         for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
498                 ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
499                 LbmControlSet *cset = mpControl->mCons[cpssi];
500                 
501                 cparts->setRadiusAtt(cset->mcRadiusAtt.get(mSimulationTime));
502                 cparts->setRadiusVel(cset->mcRadiusVel.get(mSimulationTime));
503                 cparts->setInfluenceAttraction(cset->mcForceAtt.get(mSimulationTime) );
504                 cparts->setInfluenceMaxdist(cset->mcForceMaxd.get(mSimulationTime) );
505                 cparts->setRadiusMinMaxd(cset->mcRadiusMind.get(mSimulationTime));
506                 cparts->setRadiusMaxd(cset->mcRadiusMaxd.get(mSimulationTime));
507                 cparts->calculateKernelWeight(); // always necessary!?
508                 cparts->setOffset( vec2L(cset->mcCpOffset.get(mSimulationTime)) );
509                 cparts->setScale(  vec2L(cset->mcCpScale.get(mSimulationTime)) );
510
511                 cparts->setInfluenceVelocity( cset->mcForceVel.get(mSimulationTime), mLevel[fineLev].timestep );
512                 cparts->setLastOffset( vec2L(cset->mcCpOffset.get(mSimulationTime-mLevel[fineLev].timestep)) );
513                 cparts->setLastScale(  vec2L(cset->mcCpScale.get(mSimulationTime-mLevel[fineLev].timestep)) );
514                 
515         }
516
517         // check actual values
518         LbmFloat iatt  = ABS(mpControl->mCons[0]->mCparts->getInfluenceAttraction());
519         LbmFloat ivel  = mpControl->mCons[0]->mCparts->getInfluenceVelocity();
520         LbmFloat imaxd = mpControl->mCons[0]->mCparts->getInfluenceMaxdist();
521         //errMsg("FINCIT","iatt="<<iatt<<" ivel="<<ivel<<" imaxd="<<imaxd);
522         for(int cpssi=1; cpssi<(int)mpControl->mCons.size(); cpssi++) {
523                 LbmFloat iatt2  = ABS(mpControl->mCons[cpssi]->mCparts->getInfluenceAttraction());
524                 LbmFloat ivel2  = mpControl->mCons[cpssi]->mCparts->getInfluenceVelocity();
525                 LbmFloat imaxd2 = mpControl->mCons[cpssi]->mCparts->getInfluenceMaxdist();
526                 
527                 // we allow negative attraction force here!
528                 if(iatt2 > iatt)   iatt = iatt2;
529                 
530                 if(ivel2 >ivel)   ivel = ivel2;
531                 if(imaxd2>imaxd)  imaxd= imaxd2;
532                 //errMsg("FINCIT"," "<<cpssi<<" iatt2="<<iatt2<<" ivel2="<<ivel2<<" imaxd2="<<imaxd<<" NEW "<<" iatt="<<iatt<<" ivel="<<ivel<<" imaxd="<<imaxd);
533         }
534
535         if(iatt==0. && ivel==0. && imaxd==0.) {
536                 debMsgStd("ControlData::initControl",DM_MSG,"Skipped, all zero...",4);
537                 return;
538         }
539         //iatt  = mpControl->mCons[1]->mCparts->getInfluenceAttraction(); //ivel  = mpControl->mCons[1]->mCparts->getInfluenceVelocity(); //imaxd = mpControl->mCons[1]->mCparts->getInfluenceMaxdist(); // TTTTTT
540
541         // do control setup
542         for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
543                 ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
544                 ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
545
546                 // TEST!?
547                 bool radmod = false;
548                 const LbmFloat minRadSize = mLevel[coarseLev].nodeSize * 1.5;
549                 if((cparts->getRadiusAtt()>0.) && (cparts->getRadiusAtt()<minRadSize) && (!radmod) ) {
550                         LbmFloat radfac = minRadSize / cparts->getRadiusAtt(); radmod=true;
551                         debMsgStd("ControlData::initControl",DM_MSG,"Modified radii att, fac="<<radfac, 7);
552                         cparts->setRadiusAtt(cparts->getRadiusAtt()*radfac);
553                         cparts->setRadiusVel(cparts->getRadiusVel()*radfac);
554                         cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
555                         cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
556                 } else if((cparts->getRadiusVel()>0.) && (cparts->getRadiusVel()<minRadSize) && (!radmod) ) {
557                         LbmFloat radfac = minRadSize / cparts->getRadiusVel();
558                         debMsgStd("ControlData::initControl",DM_MSG,"Modified radii vel, fac="<<radfac, 7);
559                         cparts->setRadiusVel(cparts->getRadiusVel()*radfac);
560                         cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
561                         cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
562                 } else if((cparts->getRadiusMaxd()>0.) && (cparts->getRadiusMaxd()<minRadSize) && (!radmod) ) {
563                         LbmFloat radfac = minRadSize / cparts->getRadiusMaxd();
564                         debMsgStd("ControlData::initControl",DM_MSG,"Modified radii maxd, fac="<<radfac, 7);
565                         cparts->setRadiusMaxd(cparts->getRadiusMaxd()*radfac);
566                         cparts->setRadiusMinMaxd(cparts->getRadiusMinMaxd()*radfac);
567                 }
568                 if(radmod) {
569                         debMsgStd("ControlData::initControl",DM_MSG,"Modified radii: att="<< 
570                                 cparts->getRadiusAtt()<<", vel=" << cparts->getRadiusVel()<<", maxd=" <<
571                                 cparts->getRadiusMaxd()<<", mind=" << cparts->getRadiusMinMaxd() ,5);
572                 }
573
574                 cpmotion->prepareControl( mSimulationTime+((LbmFloat)mpControl->mCpUpdateInterval)*(mpParam->getTimestep()), mpParam->getTimestep(), NULL );
575                 cparts->prepareControl( mSimulationTime+((LbmFloat)mpControl->mCpUpdateInterval)*(mpParam->getTimestep()), mpParam->getTimestep(), cpmotion );
576         }
577
578         // do control...
579         for(int lev=0; lev<=mMaxRefine; lev++) {
580                 LbmFloat levVolume = 1.;
581                 LbmFloat levForceScale = 1.;
582                 for(int ll=lev; ll<mMaxRefine; ll++) {
583                         if(LBMDIM==3) levVolume *= 8.;
584                         else levVolume *= 4.;
585                         levForceScale *= 2.;
586                 }
587                 errMsg("LbmFsgrSolver::handleCpdata","levVolume="<<levVolume<<" levForceScale="<<levForceScale );
588         //todo: scale velocity, att by level timestep!?
589                 
590         for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
591                 ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
592                 // ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
593                 
594                 // if control set is not active skip it
595                 if((cparts->getControlTimStart() > mSimulationTime) || (cparts->getControlTimEnd() < mLastSimTime))
596                 {
597                         continue;
598                 }
599
600                 const LbmFloat velLatticeScale = mLevel[lev].timestep/mLevel[lev].nodeSize;
601                 LbmFloat gsx = ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex);
602                 LbmFloat gsy = ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey);
603                 LbmFloat gsz = ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez);
604 #if LBMDIM==2
605                 gsz = gsx;
606 #endif
607                 LbmFloat goffx = mvGeoStart[0];
608                 LbmFloat goffy = mvGeoStart[1];
609                 LbmFloat goffz = mvGeoStart[2];
610
611                 //const LbmFloat cpwIncFac = 2.0;
612                 // max to two thirds of domain size
613                 const int cpw = MIN( mLevel[lev].lSizex/3, MAX( (int)( cparts->getRadiusAtt()  /gsx) +1  , 2) ); // normal kernel, att,vel
614                 const int cpkarWidth = 2*cpw+1;
615                 mpControl->mCpKernel.resize(cpkarWidth* cpkarWidth* cpkarWidth);
616                 ControlParticle cpt; cpt.reset();
617                 cpt.pos = LbmVec( (gsx*(LbmFloat)cpw)+goffx, (gsy*(LbmFloat)cpw)+goffy, (gsz*(LbmFloat)cpw)+goffz );  // optimize?
618                 cpt.density = 0.5; cpt.densityWeight = 0.5;
619 #if LBMDIM==3
620                 for(int k= 0; k<cpkarWidth; ++k) {
621 #else // LBMDIM==3
622                 { int k = cpw;
623 #endif 
624                         for(int j= 0; j<cpkarWidth; ++j) 
625                                 for(int i= 0; i<cpkarWidth; ++i) {
626                                         KERN(i,j,k).resetForces();
627                                         //LbmFloat dx = i-cpw; LbmFloat dy = j-cpw; LbmFloat dz = k-cpw;
628                                         //LbmVec dv = ( LbmVec(dx,dy,dz) );
629                                         //LbmFloat dl = norm( dv ); //LbmVec dir = dv / dl;
630                                         LbmVec pos = LbmVec( (gsx*(LbmFloat)i)+goffx, (gsy*(LbmFloat)j)+goffy, (gsz*(LbmFloat)k)+goffz );  // optimize?
631                                         cparts->calculateCpInfluenceOpt( &cpt, pos, LbmVec(0,0,0), &KERN(i,j,k)  ,1. );
632                                         /*if((CPODEBUG)&&(k==cpw)) errMsg("kern"," at "<<PRINT_IJK<<" pos"<<pos<<" cpp"<<cpt.pos 
633                                                 <<" wf:"<<KERN(i,j,k).weightAtt<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceAtt[0],KERN(i,j,k).forceAtt[1],KERN(i,j,k).forceAtt[2] )  
634                                                 <<" wf:"<<KERN(i,j,k).weightVel<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceVel[0],KERN(i,j,k).forceVel[1],KERN(i,j,k).forceVel[2] )  
635                                                 <<" wf:"<<KERN(i,j,k).maxDistance<<" wa:"<< PRINT_VEC( KERN(i,j,k).forceMaxd[0],KERN(i,j,k).forceMaxd[1],KERN(i,j,k).forceMaxd[2] )  ); // */
636                                         KERN(i,j,k).weightAtt *= 2.;
637                                         KERN(i,j,k).forceAtt *= 2.;
638                                         //KERN(i,j,k).forceAtt[1] *= 2.; KERN(i,j,k).forceAtt[2] *= 2.;
639                                         KERN(i,j,k).weightVel *= 2.;
640                                         KERN(i,j,k).forceVel *= 2.;
641                                         //KERN(i,j,k).forceVel[1] *= 2.; KERN(i,j,k).forceVel[2] *= 2.;
642                                 }
643                 }
644
645                 if(CPODEBUG) errMsg("cpw"," = "<<cpw<<" f"<< cparts->getRadiusAtt()<<" gsx"<<gsx<<" kpw"<<cpkarWidth); // DEBUG
646                 // first cp loop - add att and vel forces
647                 for(int cppi=0; cppi<cparts->getSize(); cppi++) {
648                         ControlParticle *cp = cparts->getParticle(cppi);
649                         if(cp->influence<=0.) continue;
650                         const int cpi = (int)( (cp->pos[0]-goffx)/gsx );
651                         const int cpj = (int)( (cp->pos[1]-goffy)/gsy );
652                         int       cpk = (int)( (cp->pos[2]-goffz)/gsz );
653                         /*if( ((LBMDIM==3)&&(BOUNDSKIP(cpk - cpwsm, getForZMinBnd(), getForZMaxBnd(lev) ))) ||
654                                 ((LBMDIM==3)&&(BOUNDSKIP(cpk + cpwsm, getForZMinBnd(), getForZMaxBnd(lev) ))) ||
655                                 BOUNDSKIP(cpj - cpwsm, 0, mLevel[lev].lSizey ) ||
656                                 BOUNDSKIP(cpj + cpwsm, 0, mLevel[lev].lSizey ) ||
657                                 BOUNDSKIP(cpi - cpwsm, 0, mLevel[lev].lSizex ) ||
658                                 BOUNDSKIP(cpi + cpwsm, 0, mLevel[lev].lSizex ) ) {
659                                 continue;
660                                 } // */
661                         int is,ie,js,je,ks,ke;
662                         ks = BOUNDCHECK(cpk - cpw, getForZMinBnd(), getForZMaxBnd(lev) );
663                         ke = BOUNDCHECK(cpk + cpw, getForZMinBnd(), getForZMaxBnd(lev) );
664                         js = BOUNDCHECK(cpj - cpw, 0, mLevel[lev].lSizey );
665                         je = BOUNDCHECK(cpj + cpw, 0, mLevel[lev].lSizey );
666                         is = BOUNDCHECK(cpi - cpw, 0, mLevel[lev].lSizex );
667                         ie = BOUNDCHECK(cpi + cpw, 0, mLevel[lev].lSizex );
668                         if(LBMDIM==2) { cpk = 0; ks = 0; ke = 1; }
669                         if(CPODEBUG) errMsg("cppft","i"<<cppi<<" cpw"<<cpw<<" gpos"<<PRINT_VEC(cpi,cpj,cpk)<<"   i:"<<is<<","<<ie<<"   j:"<<js<<","<<je<<"   k:"<<ks<<","<<ke<<" "); // DEBUG
670                         cpInfs++;
671
672                         for(int k= ks; k<ke; ++k) {
673                                 for(int j= js; j<je; ++j) {
674
675                                         CellFlagType *pflag = &RFLAG(lev,is,j,k, mLevel[lev].setCurr);
676                                         ControlForces *kk = &KERN( is-cpi+cpw, j-cpj+cpw, k-cpk+cpw);
677                                         ControlForces *ff = &LBMGET_FORCE(lev,is,j,k); 
678                                         pflag--; kk--; ff--;
679
680                                         for(int i= is; i<ie; ++i) {
681                                                 // first cp loop (att,vel)
682                                                 pflag++; kk++; ff++;
683
684                                                 //add weight for bnd cells
685                                                 const LbmFloat pwforce = kk->weightAtt;
686                                                 // control particle mod,
687                                                 // dont add multiple CFFluid fsgr boundaries
688                                                 if(lev==mMaxRefine) {
689                                                         //if( ( ((*pflag)&(CFFluid )) && (lev==mMaxRefine) ) ||
690                                                                         //( ((*pflag)&(CFGrNorm)) && (lev <mMaxRefine) ) ) {
691                                                         if((*pflag)&(CFFluid|CFUnused)) {
692                                                                 // check not fromcoarse?
693                                                                 cp->density += levVolume* kk->weightAtt; // old CFFluid
694                                                         } else if( (*pflag) & (CFEmpty) ) {  
695                                                                 cp->density -= levVolume* 0.5; 
696                                                         } else { //if( ((*pflag) & (CFBnd)) ) {  
697                                                                 cp->density -= levVolume* 0.2;  // penalty
698                                                         }
699                                                 } else {
700                                                         //if((*pflag)&(CFGrNorm)) {
701                                                                 //cp->density += levVolume* kk->weightAtt; // old CFFluid
702                                                         //} 
703                                                 }
704                                                 //else if(!((*pflag) & (CFUnused)) ) {  cp->density -= levVolume* 0.2; } // penalty
705
706                                                 if( (*pflag) & (CFFluid|CFInter) )  // RFLAG_check
707                                                 {
708
709                                                         cpChecks++;
710                                                         //const LbmFloat pwforce = kk->weightAtt;
711                                                         LbmFloat pwvel = kk->weightVel;
712                                                         if((pwforce==0.)&&(pwvel==0.)) { continue; }
713                                                         ff->weightAtt += 1e-6; // for distance
714
715                                                         if(pwforce>0.) {
716                                                                 ff->weightAtt += pwforce *cp->densityWeight *cp->influence;
717                                                                 ff->forceAtt += kk->forceAtt *levForceScale *cp->densityWeight *cp->influence;
718
719                                                                 // old fill handling here
720                                                                 const int workSet =mLevel[lev].setCurr;
721                                                                 LbmFloat ux=0., uy=0., uz=0.;
722                                                                 FORDF1{  
723                                                                         const LbmFloat dfn = QCELL(lev, i,j,k, workSet, l);
724                                                                         ux  += (this->dfDvecX[l]*dfn);
725                                                                         uy  += (this->dfDvecY[l]*dfn); 
726                                                                         uz  += (this->dfDvecZ[l]*dfn); 
727                                                                 }
728                                                                 // control particle mod
729                                                                 cp->avgVelWeight += levVolume*pwforce;
730                                                                 cp->avgVelAcc += LbmVec(ux,uy,uz) * levVolume*pwforce;
731                                                         }
732
733                                                         if(pwvel>0.) {
734                                                                 // TODO make switch? vel.influence depends on density weight... 
735                                                                 // (reduced lowering with 0.75 factor)
736                                                                 pwvel *=  cp->influence *(1.-0.75*cp->densityWeight);
737                                                                 // control particle mod
738                                                                 // todo use Omega instead!?
739                                                                 ff->forceVel += cp->vel*levVolume*pwvel * velLatticeScale; // levVolume?
740                                                                 ff->weightVel += levVolume*pwvel; // levVolume?
741                                                                 ff->compAv += cp->avgVel*levVolume*pwvel; // levVolume?
742                                                                 ff->compAvWeight += levVolume*pwvel; // levVolume?
743                                                         }
744
745                                                         if(CPODEBUG) errMsg("cppft","i"<<cppi<<" at "<<PRINT_IJK<<" kern:"<<
746                                                                         PRINT_VEC(i-cpi+cpw, j-cpj+cpw, k-cpk+cpw )
747                                                                         //<<" w:"<<ff->weightAtt<<" wa:"
748                                                                         //<<PRINT_VEC( ff->forceAtt[0],ff->forceAtt[1],ff->forceAtt[2] )  
749                                                                         //<<" v:"<<ff->weightVel<<" wv:"
750                                                                         //<<PRINT_VEC( ff->forceVel[0],ff->forceVel[1],ff->forceVel[2] )  
751                                                                         //<<" v:"<<ff->maxDistance<<" wv:"
752                                                                         //<<PRINT_VEC( ff->forceMaxd[0],ff->forceMaxd[1],ff->forceMaxd[2] )  
753                                                                         );
754                                                 } // celltype
755
756                                         } // ijk
757                                 } // ijk
758                         } // ijk
759                 } // cpi, end first cp loop (att,vel)
760                 debMsgStd("LbmFsgrSolver::handleCpdata",DM_MSG,"Force cpgrid "<<cpssi<<" generated checks:"<<cpChecks<<" infs:"<<cpInfs ,9);
761         } //cpssi
762         } // lev
763
764         // second loop
765         for(int lev=0; lev<=mMaxRefine; lev++) {
766                 LbmFloat levVolume = 1.;
767                 LbmFloat levForceScale = 1.;
768                 for(int ll=lev; ll<mMaxRefine; ll++) {
769                         if(LBMDIM==3) levVolume *= 8.;
770                         else levVolume *= 4.;
771                         levForceScale *= 2.;
772                 }
773         // prepare maxd forces
774         for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
775                 ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
776
777                 // WARNING copied from above!
778                 const LbmFloat velLatticeScale = mLevel[lev].timestep/mLevel[lev].nodeSize;
779                 LbmFloat gsx = ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex);
780                 LbmFloat gsy = ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey);
781                 LbmFloat gsz = ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez);
782 #if LBMDIM==2
783                 gsz = gsx;
784 #endif
785                 LbmFloat goffx = mvGeoStart[0];
786                 LbmFloat goffy = mvGeoStart[1];
787                 LbmFloat goffz = mvGeoStart[2];
788
789                 //const LbmFloat cpwIncFac = 2.0;
790                 const int mdw = MIN( mLevel[lev].lSizex/2, MAX( (int)( cparts->getRadiusMaxd() /gsx) +1  , 2) ); // wide kernel, md
791                 const int mdkarWidth = 2*mdw+1;
792                 mpControl->mMdKernel.resize(mdkarWidth* mdkarWidth* mdkarWidth);
793                 ControlParticle cpt; cpt.reset();
794                 cpt.density = 0.5; cpt.densityWeight = 0.5;
795                 cpt.pos = LbmVec( (gsx*(LbmFloat)mdw)+goffx, (gsy*(LbmFloat)mdw)+goffy, (gsz*(LbmFloat)mdw)+goffz );  // optimize?
796 #if LBMDIM==3
797                 for(int k= 0; k<mdkarWidth; ++k) {
798 #else // LBMDIM==3
799                 { int k = mdw;
800 #endif 
801                         for(int j= 0; j<mdkarWidth; ++j) 
802                                 for(int i= 0; i<mdkarWidth; ++i) {
803                                         MDKERN(i,j,k).resetForces();
804                                         LbmVec pos = LbmVec( (gsx*(LbmFloat)i)+goffx, (gsy*(LbmFloat)j)+goffy, (gsz*(LbmFloat)k)+goffz );  // optimize?
805                                         cparts->calculateMaxdForce( &cpt, pos, &MDKERN(i,j,k)  );
806                                 }
807                 }
808
809                 // second cpi loop, maxd forces
810                 if(cparts->getInfluenceMaxdist()>0.) {
811                         for(int cppi=0; cppi<cparts->getSize(); cppi++) {
812                                 ControlParticle *cp = cparts->getParticle(cppi);
813                                 if(cp->influence<=0.) continue;
814                                 const int cpi = (int)( (cp->pos[0]-goffx)/gsx );
815                                 const int cpj = (int)( (cp->pos[1]-goffy)/gsy );
816                                 int       cpk = (int)( (cp->pos[2]-goffz)/gsz );
817
818                                 int is,ie,js,je,ks,ke;
819                                 ks = BOUNDCHECK(cpk - mdw, getForZMinBnd(), getForZMaxBnd(lev) );
820                                 ke = BOUNDCHECK(cpk + mdw, getForZMinBnd(), getForZMaxBnd(lev) );
821                                 js = BOUNDCHECK(cpj - mdw, 0, mLevel[lev].lSizey );
822                                 je = BOUNDCHECK(cpj + mdw, 0, mLevel[lev].lSizey );
823                                 is = BOUNDCHECK(cpi - mdw, 0, mLevel[lev].lSizex );
824                                 ie = BOUNDCHECK(cpi + mdw, 0, mLevel[lev].lSizex );
825                                 if(LBMDIM==2) { cpk = 0; ks = 0; ke = 1; }
826                                 if(CPODEBUG) errMsg("cppft","i"<<cppi<<" mdw"<<mdw<<" gpos"<<PRINT_VEC(cpi,cpj,cpk)<<"   i:"<<is<<","<<ie<<"   j:"<<js<<","<<je<<"   k:"<<ks<<","<<ke<<" "); // DEBUG
827                                 cpInfs++;
828
829                                 for(int k= ks; k<ke; ++k)
830                                  for(int j= js; j<je; ++j) {
831                                         CellFlagType *pflag = &RFLAG(lev,is-1,j,k, mLevel[lev].setCurr);
832                                         for(int i= is; i<ie; ++i) {
833                                                 // second cpi loop, maxd forces
834                                                 pflag++;
835                                                 if( (*pflag) & (CFFluid|CFInter) )  // RFLAG_check
836                                                 {
837                                                         cpChecks++;
838                                                         ControlForces *ff = &LBMGET_FORCE(lev,i,j,k); 
839                                                         if(ff->weightAtt == 0.) {
840                                                                 ControlForces *kk = &MDKERN( i-cpi+mdw, j-cpj+mdw, k-cpk+mdw);
841                                                                 const LbmFloat pmdf = kk->maxDistance;
842                                                                 if((ff->maxDistance > pmdf) || (ff->maxDistance<0.))
843                                                                         ff->maxDistance = pmdf;
844                                                                 ff->forceMaxd = kk->forceMaxd;
845                                                                 // todo use Omega instead!?
846                                                                 ff->forceVel = cp->vel* velLatticeScale;
847                                                         }
848                                                 } // celltype
849                                 } } // ijk
850                         } // cpi, md loop 
851                 } // maxd inf>0 */
852
853
854                 debMsgStd("ControlData::initControl",DM_MSG,"Maxd cpgrid "<<cpssi<<" generated checks:"<<cpChecks<<" infs:"<<cpInfs ,9);
855         } //cpssi
856
857         // normalize, only done once for the whole array
858         mpControl->mCons[0]->mCparts->finishControl( mpControl->mCpForces[lev], iatt,ivel,imaxd );
859
860         } // lev loop
861
862         myTime_t cpend = getTime(); 
863         debMsgStd("ControlData::handleCpdata",DM_MSG,"Time for cpgrid generation:"<< getTimeString(cpend-cpstart)<<", checks:"<<cpChecks<<" infs:"<<cpInfs<<" " ,8);
864
865         // warning, may return  before
866 }
867
868 #if LBM_USE_GUI==1
869
870 #define USE_GLUTILITIES
871 #include "../gui/gui_utilities.h"
872
873 void LbmFsgrSolver::cpDebugDisplay(int dispset)
874 {
875         for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) {
876                 ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts;
877                 //ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion;
878                 // display cp parts
879                 const bool cpCubes = false;
880                 const bool cpDots = true;
881                 const bool cpCpdist = true;
882                 const bool cpHideIna = true;
883                 glShadeModel(GL_FLAT);
884                 glDisable( GL_LIGHTING ); // dont light lines
885
886                 // dot influence
887                 if((mpControl->mDebugCpscale>0.) && cpDots) {
888                         glPointSize(mpControl->mDebugCpscale * 8.);
889                         glBegin(GL_POINTS);
890                         for(int i=0; i<cparts->getSize(); i++) {
891                                 if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue;
892                                 ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) );
893                                 //LbmFloat halfsize = 0.5; 
894                                 LbmFloat scale = cparts->getParticle(i)->densityWeight;
895                                 //glColor4f( scale,scale,scale,scale );
896                                 glColor4f( 0.,scale,0.,scale );
897                                 glVertex3f( org[0],org[1],org[2] );
898                                 //errMsg("lbmDebugDisplay","CP "<<i<<" at "<<org); // DEBUG
899                         }
900                         glEnd();
901                 }
902
903                 // cp positions
904                 if((mpControl->mDebugCpscale>0.) && cpDots) {
905                         glPointSize(mpControl->mDebugCpscale * 3.);
906                         glBegin(GL_POINTS); 
907                         glColor3f( 0,1,0 );
908                 }
909                 for(int i=0; i<cparts->getSize(); i++) {
910                         if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue;
911                         ntlVec3Gfx  org( vec2G(cparts->getParticle(i)->pos ) );
912                         LbmFloat halfsize = 0.5; 
913                         LbmFloat scale = cparts->getRadiusAtt() * cparts->getParticle(i)->densityWeight;
914                         if(cpCubes){    glLineWidth( 1 ); 
915                                 glColor3f( 1,1,1 );
916                                 ntlVec3Gfx s = org-(halfsize * (scale)); 
917                                 ntlVec3Gfx e = org+(halfsize * (scale)); 
918                                 drawCubeWire( s,e ); }
919                         if((mpControl->mDebugCpscale>0.) && cpDots) {
920                                 glVertex3f( org[0],org[1],org[2] );
921                         }
922                 }
923                 if(cpDots) glEnd();
924
925                 if(mpControl->mDebugAvgVelScale>0.) {
926                         const float scale = mpControl->mDebugAvgVelScale;
927
928                         glColor3f( 1.0,1.0,1 );
929                         glBegin(GL_LINES); 
930                         for(int i=0; i<cparts->getSize(); i++) {
931                                 if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue;
932                                 ntlVec3Gfx  org( vec2G(cparts->getParticle(i)->pos ) );
933
934                                 //errMsg("CPAVGVEL","i"<<i<<" pos"<<org<<" av"<<cparts->getParticle(i)->avgVel);// DEBUG
935                                 float dx = cparts->getParticle(i)->avgVel[0];
936                                 float dy = cparts->getParticle(i)->avgVel[1];
937                                 float dz = cparts->getParticle(i)->avgVel[2];
938                                 dx *= scale; dy *= scale; dz *= scale;
939                                 glVertex3f( org[0],org[1],org[2] );
940                                 glVertex3f( org[0]+dx,org[1]+dy,org[2]+dz );
941                         }
942                         glEnd();
943                 } // */
944
945                 if( (LBMDIM==2) && (cpCpdist) ) {
946                         
947                         // debug, for use of e.g. LBMGET_FORCE LbmControlData *mpControl = this;
948 #                       define TESTGET_FORCE(lev,i,j,k)   mpControl->mCpForces[lev][ ((k*mLevel[lev].lSizey)+j)*mLevel[lev].lSizex+i ]
949         
950                         glBegin(GL_LINES);
951                         //const int lev=0; 
952                         for(int lev=0; lev<=mMaxRefine; lev++) {
953                         FSGR_FORIJK_BOUNDS(lev) {
954                                         LbmVec pos = LbmVec( 
955                                                 ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex) * ((LbmFloat)i+0.5) + mvGeoStart[0], 
956                                                 ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey) * ((LbmFloat)j+0.5) + mvGeoStart[1], 
957                                                 ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez) * ((LbmFloat)k+0.5) + mvGeoStart[2]  );
958                                         if(LBMDIM==2) pos[2] = ((mvGeoEnd[2]-mvGeoStart[2])*0.5 + mvGeoStart[2]);
959
960                                         if((mpControl->mDebugMaxdScale>0.) && (TESTGET_FORCE(lev,i,j,k).weightAtt<=0.) )
961                                         if(TESTGET_FORCE(lev,i,j,k).maxDistance>=0.) 
962                                         if(TESTGET_FORCE(lev,i,j,k).maxDistance<CPF_MAXDINIT ) {
963                                                 const float scale = mpControl->mDebugMaxdScale*10001.;
964                                                 float dx = TESTGET_FORCE(lev,i,j,k).forceMaxd[0];
965                                                 float dy = TESTGET_FORCE(lev,i,j,k).forceMaxd[1];
966                                                 float dz = TESTGET_FORCE(lev,i,j,k).forceMaxd[2];
967                                                 dx *= scale; dy *= scale; dz *= scale;
968                                                 glColor3f( 0,1,0 );
969                                                 glVertex3f( pos[0],pos[1],pos[2] );
970                                                 glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
971                                         } // */
972                                         if((mpControl->mDebugAttScale>0.) && (TESTGET_FORCE(lev,i,j,k).weightAtt>0.)) {
973                                                 const float scale = mpControl->mDebugAttScale*100011.;
974                                                 float dx = TESTGET_FORCE(lev,i,j,k).forceAtt[0];
975                                                 float dy = TESTGET_FORCE(lev,i,j,k).forceAtt[1];
976                                                 float dz = TESTGET_FORCE(lev,i,j,k).forceAtt[2];
977                                                 dx *= scale; dy *= scale; dz *= scale;
978                                                 glColor3f( 1,0,0 );
979                                                 glVertex3f( pos[0],pos[1],pos[2] );
980                                                 glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
981                                         } // */
982                                         // why check maxDistance?
983                                         if((mpControl->mDebugVelScale>0.) && (TESTGET_FORCE(lev,i,j,k).maxDistance+TESTGET_FORCE(lev,i,j,k).weightVel>0.)) {
984                                                 float scale = mpControl->mDebugVelScale*1.;
985                                                 float wvscale = TESTGET_FORCE(lev,i,j,k).weightVel;
986                                                 float dx = TESTGET_FORCE(lev,i,j,k).forceVel[0];
987                                                 float dy = TESTGET_FORCE(lev,i,j,k).forceVel[1];
988                                                 float dz = TESTGET_FORCE(lev,i,j,k).forceVel[2];
989                                                 scale *= wvscale;
990                                                 dx *= scale; dy *= scale; dz *= scale;
991                                                 glColor3f( 0.2,0.2,1 );
992                                                 glVertex3f( pos[0],pos[1],pos[2] );
993                                                 glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
994                                         } // */
995                                         if((mpControl->mDebugCompavScale>0.) && (TESTGET_FORCE(lev,i,j,k).compAvWeight>0.)) {
996                                                 const float scale = mpControl->mDebugCompavScale*1.;
997                                                 float dx = TESTGET_FORCE(lev,i,j,k).compAv[0];
998                                                 float dy = TESTGET_FORCE(lev,i,j,k).compAv[1];
999                                                 float dz = TESTGET_FORCE(lev,i,j,k).compAv[2];
1000                                                 dx *= scale; dy *= scale; dz *= scale;
1001                                                 glColor3f( 0.2,0.2,1 );
1002                                                 glVertex3f( pos[0],pos[1],pos[2] );
1003                                                 glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz );
1004                                         } // */
1005                         } // att,maxd
1006                         }
1007                         glEnd();
1008                 }
1009         } // cpssi
1010
1011         //fprintf(stderr,"BLA\n");
1012         glEnable( GL_LIGHTING ); // dont light lines
1013         glShadeModel(GL_SMOOTH);
1014 }
1015
1016 #else // LBM_USE_GUI==1
1017 void LbmFsgrSolver::cpDebugDisplay(int dispset) { }
1018 #endif // LBM_USE_GUI==1
1019
1020