// get the min and max value for all time steps int Solution::GetMinMaxValueAll(VECTOR3& minVal, VECTOR3& maxVal) { minVal = m_pMinValue[0]; maxVal = m_pMaxValue[0]; for(int tFor = 1; tFor < m_nTimeSteps; tFor++) { if(minVal.GetMag() > m_pMinValue[tFor].GetMag()) minVal = m_pMinValue[tFor]; if(maxVal.GetMag() < m_pMaxValue[tFor].GetMag()) maxVal = m_pMaxValue[tFor]; } return 1; }
float FieldData::getFieldMag(float point[3]) { VECTOR3 pos(point[0],point[1],point[2]); VECTOR3 vel; int rc = pField->getFieldValue( pos, (float)timeStep, vel); if (rc < 0) return -1.f; return vel.GetMag(); }
// 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, 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; }
////////////////////////////////////////////////////////////////////////// // Compute streamlines. // output // listSeedTraces: For each seed, return a list keeping the trace it // advects ////////////////////////////////////////////////////////////////////////// //New version, uses FlowLineData instead of points array to write results of advection. void vtCStreamLine::computeStreamLine(float curTime, FlowLineData* container){ m_fCurrentTime = curTime; vtListParticleIter sIter; int istat; int seedNum = 0; for(sIter = m_lSeeds.begin(); sIter != m_lSeeds.end(); ++sIter) { vtParticleInfo* thisSeed = *sIter; if(thisSeed->itsValidFlag == 1) // valid seed { if(m_itsTraceDir & BACKWARD_DIR) { vtListSeedTrace* backTrace; list<float>* stepList; backTrace = new vtListSeedTrace; stepList = new list<float>; istat = computeFieldLine(BACKWARD, STEADY, *backTrace, *stepList, thisSeed->m_pointInfo); SampleFieldline(container, seedNum, BACKWARD, backTrace, stepList, true, istat ); delete backTrace; delete stepList; } else { //must be pure forward, set start point container->setFlowStart(seedNum, 0); } if(m_itsTraceDir & FORWARD_DIR) { vtListSeedTrace* forwardTrace; list<float>* stepList; forwardTrace = new vtListSeedTrace; stepList = new list<float>; istat = computeFieldLine(FORWARD,STEADY, *forwardTrace, *stepList, thisSeed->m_pointInfo); SampleFieldline(container, seedNum, FORWARD, forwardTrace, stepList, true, istat); delete forwardTrace; delete stepList; } else { //Must be pure backward, establish end of flowline: container->setFlowEnd(seedNum, 0); } } else // out of data region. Just mark seed as end, don't advect. { float x = thisSeed->m_pointInfo.phyCoord.x(); float y = thisSeed->m_pointInfo.phyCoord.y(); float z = thisSeed->m_pointInfo.phyCoord.z(); container->setFlowPoint(seedNum, 0, x,y,z); if(container->getMaxLength(BACKWARD) > 0) container->setFlowPoint(seedNum, -1, END_FLOW_FLAG,0.f,0.f); if(container->getMaxLength(FORWARD) > 0) container->setFlowPoint(seedNum, 1, END_FLOW_FLAG,0.f,0.f); if (container->doSpeeds()){ PointInfo pointInfo; VECTOR3 nodeData; float t = m_pField->GetStartTime(); pointInfo.phyCoord.Set(x,y,z); m_pField->getFieldValue(pointInfo.phyCoord, t, nodeData); container->setSpeed(seedNum, 0, nodeData.GetMag()/m_pField->getTimeScaleFactor()); } container->setFlowStart(seedNum, 0); container->setFlowEnd(seedNum, 0); } seedNum++; } }
int vtCTimeVaryingFieldLine::advectParticle(INTEG_ORD int_order, vtParticleInfo& initialPoint, float initialTime, float finalTime, vtListTimeSeedTrace& seedTrace) { int count = 0, istat, res; PointInfo seedInfo; PointInfo thisParticle, prevParticle, second_prevParticle; PointInfo third_prevParticle; float dt, dt_attempt, dt_estimate, cell_volume, mag, curTime, prevCurTime; 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; VECTOR4 *p = new VECTOR4; (*p)[0] = seedInfo.phyCoord[0]; (*p)[1] = seedInfo.phyCoord[1]; (*p)[2] = seedInfo.phyCoord[2]; (*p)[3] = initialTime; seedTrace.push_back(p); curTime = initialTime; count++; // get the initial stepsize dt = m_fInitialStepSize; if(m_adaptStepSize) { 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) { third_prevParticle = second_prevParticle; second_prevParticle = prevParticle; prevParticle = thisParticle; prevCurTime = curTime; dt_attempt = dt; 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); // check if the step failed if(istat == FAIL) { if(!m_adaptStepSize) { // can't change the step size, so advection just ends return OKAY; } if(dt_attempt == m_fMinStepSize) { // tried to take a step with the min step size, but failed, // 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; } } VECTOR4 *p = new VECTOR4; (*p)[0] = thisParticle.phyCoord[0]; (*p)[1] = thisParticle.phyCoord[1]; (*p)[2] = thisParticle.phyCoord[2]; (*p)[3] = curTime; seedTrace.push_back(p); count++; if(!m_adaptStepSize) { // change step size to previously 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, curTime)) { return OUT_OF_BOUND; } // check if point is at critical point 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; } 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; }