// streamline advects as far as possible till the boundary or terminates at // critical points. only two cases will happen: OUT_OF_BOUND & CRITICAL_POINT int vtCStreamLine::executeInfiniteAdvection(TIME_DIR time_dir, TIME_DEP time_dep, vtListSeedTrace& seedTrace, float& totalStepsize, vector<float>* vStepsize) { int istat; vtParticleInfo* thisSeed; PointInfo thisParticle, prevParticle, second_prevParticle, seedInfo; vtListParticleIter sIter; float dt, dt_estimate, cell_volume, mag, curTime; VECTOR3 vel; INTEG_ORD integ_ord; // initialize integ_ord = m_integrationOrder; sIter = m_lSeeds.begin(); thisSeed = *sIter; seedInfo = thisSeed->m_pointInfo; seedTrace.clear(); totalStepsize = 0.0; // the first point seedTrace.push_back(new VECTOR3(seedInfo.phyCoord)); istat = m_pField->at_phys(seedInfo.fromCell, seedInfo.phyCoord, seedInfo, m_fCurrentTime, vel); if((fabs(vel[0]) < m_fStationaryCutoff) && (fabs(vel[1]) < m_fStationaryCutoff) && (fabs(vel[2]) < m_fStationaryCutoff)) return CRITICAL_POINT; thisParticle = seedInfo; curTime = m_fCurrentTime; // get the initial stepsize cell_volume = m_pField->volume_of_cell(seedInfo.inCell); mag = vel.GetMag(); if(fabs(mag) < 1.0e-6f) dt_estimate = 1.0e-5f; else dt_estimate = pow(cell_volume, (float)0.3333333f) / mag; dt = m_fInitialStepSize * dt_estimate; #ifdef DEBUG fprintf(fDebugOut, "****************new particle*****************\n"); fprintf(fDebugOut, "seed: %f, %f, %f with step size %f\n", seedInfo.phyCoord[0],seedInfo.phyCoord[1],seedInfo.phyCoord[2],dt); #endif // start to advect while(true) { second_prevParticle = prevParticle; prevParticle = thisParticle; // take a proper step, also calculates a new step size for the next step if(integ_ord == SECOND || integ_ord == FOURTH) istat = oneStepGeometric(integ_ord, time_dir, time_dep, thisParticle, prevParticle, second_prevParticle, &curTime, &dt, seedTrace.size()); else if(integ_ord == RK45) istat = oneStepEmbedded(integ_ord, time_dir, time_dep, thisParticle, &curTime, &dt); else return OUT_OF_BOUND; if(istat == OUT_OF_BOUND) // out of boundary { // find the boundary intersection point VECTOR3 intersectP, startP, endP; float oldStepsize, stepSize; oldStepsize = stepSize = dt; startP = prevParticle.phyCoord; endP = thisParticle.phyCoord; m_pField->BoundaryIntersection(intersectP, startP, endP, &stepSize, oldStepsize); totalStepsize += stepSize; seedTrace.push_back(new VECTOR3(intersectP)); if(vStepsize != NULL) vStepsize->push_back(stepSize); return OUT_OF_BOUND; } // find the loop list<VECTOR3*>::iterator searchIter; searchIter = seedTrace.end(); searchIter--; for(; searchIter != seedTrace.begin(); searchIter--) { if(thisParticle.phyCoord == **searchIter) // loop return CRITICAL_POINT; } m_pField->at_phys(thisParticle.fromCell, thisParticle.phyCoord, thisParticle, m_fCurrentTime, vel); seedTrace.push_back(new VECTOR3(thisParticle.phyCoord)); if(vStepsize != NULL) vStepsize->push_back(dt); totalStepsize += dt; #ifdef DEBUG fprintf(fDebugOut, "***************advected particle***************\n"); fprintf(fDebugOut, "pos = (%f, %f, %f), vel = (%f, %f, %f) with step size %f, total step size %f\n", thisParticle.phyCoord[0], thisParticle.phyCoord[1], thisParticle.phyCoord[2], vel[0], vel[1], vel[2], dt, totalStepsize); #endif if(totalStepsize > 4000.0) { printf("curl\n"); vel.Set(0.0, 0.0, 0.0); } if((fabs(vel[0]) < m_fStationaryCutoff) && (fabs(vel[1]) < m_fStationaryCutoff) && (fabs(vel[2]) < m_fStationaryCutoff)) return CRITICAL_POINT; if((int)seedTrace.size() > 2) adapt_step(second_prevParticle.phyCoord, prevParticle.phyCoord, thisParticle.phyCoord, &dt); } return OUT_OF_BOUND; }
int vtCStreamLine::computeFieldLine(TIME_DIR time_dir, TIME_DEP time_dep, vtListSeedTrace& seedTrace, list<float>& stepList, PointInfo& seedInfo) { int istat; PointInfo thisParticle; double dt, cell_vol, mag; double curTime; VECTOR3 vel; float totalStepsize = 0.0; bool onAdaptive = true; int nSetAdaptiveCount = 0; // the first particle thisParticle = seedInfo; seedTrace.push_back(new VECTOR3(seedInfo.phyCoord)); curTime = (double)m_fCurrentTime; istat = m_pField->getFieldValue(seedInfo.phyCoord, m_fCurrentTime, vel); if(istat == OUT_OF_BOUND) return OUT_OF_BOUND; // the advection is out of boundary if(istat == MISSING_VALUE ||((abs(vel[0]) < m_fStationaryCutoff) && (abs(vel[1]) < m_fStationaryCutoff) && (abs(vel[2]) < m_fStationaryCutoff))) return CRITICAL_POINT; // this is critical point // get the initial step size cell_vol = m_pField->GetMinCellVolume(); mag = vel.GetDMag(); dt = m_fInitStepSize * cell_vol / mag; //Determine the value of mag*dt to project 10 times init size. double maxMagDt = 10.*dt*mag; int rollbackCount = 0; // start to advect while(totalStepsize < (float)((m_nMaxsize-1)*m_fSamplingRate)) { bool doingRetrace = false; int retrace = true; while(retrace) { retrace = false; for(int magTry = 0; magTry < 40; magTry++) { istat = runge_kutta4(time_dir, time_dep, thisParticle, &curTime, dt, maxMagDt); if (istat != FIELD_TOO_BIG) break; //Shrink dt by factor of 10. dt = 0.1*dt; } assert (istat != FIELD_TOO_BIG); seedTrace.push_back(new VECTOR3(thisParticle.phyCoord)); stepList.push_back(dt); if(istat == OUT_OF_BOUND) // out of boundary return OUT_OF_BOUND; m_pField->getFieldValue(thisParticle.phyCoord, m_fCurrentTime, vel); if((abs(vel[0]) < m_fStationaryCutoff) && (abs(vel[1]) < m_fStationaryCutoff) && (abs(vel[2]) < m_fStationaryCutoff)) return CRITICAL_POINT; totalStepsize += dt; // accumulation of step size nSetAdaptiveCount++; if((nSetAdaptiveCount == 2) && (onAdaptive == false)) onAdaptive = true; // just generate valid new point if(((int)seedTrace.size() > 2)&&(onAdaptive)) { double minStepsize, maxStepsize; VECTOR3 thisPhy, prevPhy, second_prevPhy; list<VECTOR3*>::iterator pIter = seedTrace.end(); pIter--; thisPhy = **pIter; pIter--; prevPhy = **pIter; pIter--; second_prevPhy = **pIter; mag = vel.GetDMag(); minStepsize = m_fInitStepSize * cell_vol / mag; maxStepsize = m_fMaxStepSize * cell_vol / mag; retrace = adapt_step(second_prevPhy, prevPhy, thisPhy, minStepsize, maxStepsize, &dt, onAdaptive); if(onAdaptive == false) nSetAdaptiveCount = 0; assert (rollbackCount < 10000);//If we got here, it's surely an infinite loop! // roll back and retrace //the doingRetrace flag is to stop double retracing (which results in infinite loop!) //Note a slightly different approach is in VTTimeVaryingFieldLine.cpp if(retrace && !doingRetrace) { seedTrace.pop_back(); seedTrace.pop_back(); thisParticle.Set(*(seedTrace.back())); totalStepsize -= stepList.back(); stepList.pop_back(); totalStepsize -= stepList.back(); stepList.pop_back(); rollbackCount++; doingRetrace = true; } else doingRetrace = false; } }// end of retrace //What was the distance advected? }// end of advection return (OKAY); }
int vtCStreamLine::computeFieldLine(TIME_DIR time_dir, INTEG_ORD integ_ord, TIME_DEP time_dep, vtListSeedTrace& seedTrace, PointInfo& seedInfo) { int count = 0, istat; PointInfo thisParticle, prevParticle, second_prevParticle; PointInfo third_prevParticle; float dt, dt_estimate, dt_attempt, mag, curTime, prevCurTime; VECTOR3 vel; float cell_volume; // the first point istat = m_pField->at_phys(seedInfo.fromCell, seedInfo.phyCoord, seedInfo, m_fCurrentTime, vel); if(istat == OUT_OF_BOUND) { return OUT_OF_BOUND; } if((fabs(vel[0]) < m_fStationaryCutoff) && (fabs(vel[1]) < m_fStationaryCutoff) && (fabs(vel[2]) < m_fStationaryCutoff)) { return CRITICAL_POINT; } thisParticle = seedInfo; seedTrace.push_back(new VECTOR3(seedInfo.phyCoord)); curTime = m_fCurrentTime; count++; // get the initial stepsize // this method was taken from the paper "Interactive Time-Dependent // Particle Tracing Using Tetrahedral Decomposition", by Kenwright and Lane dt = m_fInitialStepSize; if(m_adaptStepSize) { cell_volume = m_pField->volume_of_cell(seedInfo.inCell); mag = vel.GetMag(); if(fabs(mag) < 1.0e-6f) dt_estimate = 1.0e-5f; else dt_estimate = pow(cell_volume, (float)0.3333333f) / mag; dt = m_fInitialStepSize * dt_estimate; } #ifdef DEBUG fprintf(fDebugOut, "****************new particle*****************\n"); fprintf(fDebugOut, "seed: %f, %f, %f with step size %f\n", seedInfo.phyCoord[0],seedInfo.phyCoord[1],seedInfo.phyCoord[2],dt); #endif // start to advect while(count < m_nMaxsize) { third_prevParticle = second_prevParticle; second_prevParticle = prevParticle; prevParticle = thisParticle; prevCurTime = curTime; dt_attempt = dt; // take a proper step, also calculates a new step size for the next step if(integ_ord == SECOND || integ_ord == FOURTH) istat = oneStepGeometric(integ_ord, time_dir, time_dep, thisParticle, prevParticle, second_prevParticle, &curTime, &dt, count); else if(integ_ord == RK45) istat = oneStepEmbedded(integ_ord, time_dir, time_dep, thisParticle, &curTime, &dt); #ifdef DEBUG fprintf(fDebugOut, "point: %f, %f, %f with step size %f\n", thisParticle.phyCoord[0], thisParticle.phyCoord[1], thisParticle.phyCoord[2], dt); #endif // check if the step failed if(istat == FAIL) { if(!m_adaptStepSize) { // can't change the step size, so advection just ends return OKAY; } else if(dt_attempt == m_fMinStepSize) { // tried to take a step with the min step size, // can't go any further return OKAY; } else { // try to retake the step with a smaller step size dt = dt_attempt*0.1; if(dt < m_fMinStepSize) dt = m_fMinStepSize; thisParticle = prevParticle; prevParticle = second_prevParticle; second_prevParticle = third_prevParticle; curTime = prevCurTime; continue; } } seedTrace.push_back(new VECTOR3(thisParticle.phyCoord)); count++; if(!m_adaptStepSize) { // change step size to prevously used, since the oneStep methods // will change the value of dt dt = dt_attempt; } // check if point is outside real bounds // (bounds not counting ghost cells) if(!m_pField->IsInRealBoundaries(thisParticle)) { return OUT_OF_BOUND; } // check if point is at critical point m_pField->at_phys(thisParticle.fromCell, thisParticle.phyCoord, thisParticle, m_fCurrentTime, vel); if((fabs(vel[0]) < m_fStationaryCutoff) && (fabs(vel[1]) < m_fStationaryCutoff) && (fabs(vel[2]) < m_fStationaryCutoff)) { return CRITICAL_POINT; } } return OKAY; }
////////////////////////////////////////////////////////////////////////// // advect the particle until it goes out of boundary or vel = 0 // return back the track of advection ////////////////////////////////////////////////////////////////////////// int vtCTimeVaryingFieldLine::advectParticle(INTEG_ORD int_order, vtParticleInfo& initialPoint, float initialTime, float finalTime, vtListSeedTrace& seedTrace) { int count = 0, istat, res; PointInfo seedInfo; PointInfo thisParticle, prevParticle, second_prevParticle; float dt, dt_estimate, cell_volume, mag, curTime; VECTOR3 vel; // the first particle seedInfo = initialPoint.m_pointInfo; res = m_pField->at_phys(seedInfo.fromCell, seedInfo.phyCoord, seedInfo, initialTime, vel); if(res == OUT_OF_BOUND){ return OUT_OF_BOUND; } if((fabs(vel[0]) < m_fStationaryCutoff) && (fabs(vel[1]) < m_fStationaryCutoff) && (fabs(vel[2]) < m_fStationaryCutoff)) { return CRITICAL_POINT; } thisParticle = seedInfo; seedTrace.push_back(new VECTOR3(seedInfo.phyCoord)); curTime = initialTime; count++; // get the initial stepsize switch(m_pField->GetCellType()) { case CUBE: dt = dt_estimate = m_fInitialStepSize; break; case TETRAHEDRON: cell_volume = m_pField->volume_of_cell(seedInfo.inCell); mag = vel.GetMag(); if(fabs(mag) < 1.0e-6f) dt_estimate = 1.0e-5f; else dt_estimate = pow(cell_volume, (float)0.3333333f) / mag; dt = dt_estimate; break; default: break; } // start to advect while(count < m_nMaxsize) { second_prevParticle = prevParticle; prevParticle = thisParticle; if(int_order == SECOND || int_order == FOURTH) istat = oneStepGeometric(int_order, m_timeDir, UNSTEADY, thisParticle, prevParticle, second_prevParticle, &curTime, &dt, count); else if(int_order == RK45) istat = oneStepEmbedded(int_order, m_timeDir, UNSTEADY, thisParticle, &curTime, &dt); else return OUT_OF_BOUND; if(istat == OUT_OF_BOUND) { // out of boundary return OUT_OF_BOUND; } m_pField->at_phys(thisParticle.fromCell, thisParticle.phyCoord, thisParticle, curTime, vel); if((fabs(vel[0]) < m_fStationaryCutoff) && (fabs(vel[1]) < m_fStationaryCutoff) && (fabs(vel[2]) < m_fStationaryCutoff)) { return CRITICAL_POINT; // arrives at a critical point } else { seedTrace.push_back(new VECTOR3(thisParticle.phyCoord)); count++; } if((curTime < m_pField->GetMinTimeStep()) || (curTime > m_pField->GetMaxTimeStep())) { return OUT_OF_BOUND; } } return OKAY; }