diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLine.C b/src/postProcessing/functionObjects/field/streamLine/streamLine.C index 8336fd8f9a9144b8f3465e144421547b81b63a1a..1a7c86c1a49153b45f15cbcde112a2fae655281e 100644 --- a/src/postProcessing/functionObjects/field/streamLine/streamLine.C +++ b/src/postProcessing/functionObjects/field/streamLine/streamLine.C @@ -53,16 +53,10 @@ void Foam::streamLine::track() initialParticles ); - //Pout<< "Seeding particles." << endl; - const sampledSet& seedPoints = sampledSetPtr_(); forAll(seedPoints, i) { - //Pout<< "Seeded particle at " << seedPoints[i] - // << " at cell:" << seedPoints.cells()[i] - // << endl; - particles.addParticle ( new streamLineParticle @@ -228,15 +222,14 @@ void Foam::streamLine::track() vvInterp, UIndex, // index of U in vvInterp trackForward_, // track in +u direction + nSubCycle_, // step through cells in steps? allTracks_, allScalars_, allVectors_ ); // Track - //Pout<< "Tracking particles." << endl; particles.move(td); - //Pout<< "Finished tracking particles." << endl; } @@ -296,6 +289,19 @@ void Foam::streamLine::read(const dictionary& dict) UName_ = dict.lookupOrDefault<word>("U", "U"); dict.lookup("trackForward") >> trackForward_; dict.lookup("lifeTime") >> lifeTime_; + if (lifeTime_ < 1) + { + FatalErrorIn(":streamLine::read(const dictionary&)") + << "Illegal value " << lifeTime_ << " for lifeTime" + << exit(FatalError); + } + + dict.lookup("nSubCycle") >> nSubCycle_; + if (nSubCycle_ < 1) + { + nSubCycle_ = 1; + } + cloudName_ = dict.lookupOrDefault<word>("cloudName", "streamLine"); dict.lookup("seedSampleSet") >> seedSet_; @@ -323,7 +329,6 @@ void Foam::streamLine::execute() { // const Time& runTime = const_cast<Time&>(obr_.time()); // Pout<< "**streamLine::execute : time:" << runTime.timeName() << endl; -// Pout<< "**streamLine::execute : time:" << runTime.timeIndex() << endl; // // bool isOutputTime = false; // diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLine.H b/src/postProcessing/functionObjects/field/streamLine/streamLine.H index 55edc7efe091e92e0681fe66f51cba081af01d2e..ed39204d2230ece5b940b9881cb714940b514d4b 100644 --- a/src/postProcessing/functionObjects/field/streamLine/streamLine.H +++ b/src/postProcessing/functionObjects/field/streamLine/streamLine.H @@ -92,6 +92,9 @@ class streamLine //- Maximum lifetime (= number of cells) of particle label lifeTime_; + //- Number of subcycling steps + label nSubCycle_; + //- Optional specified name of particles word cloudName_; diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C index 56b05c88caf9b1f39c3ebf21f79258629363ce7f..7230a21345accc9cacd715176a2fe9cc8d940b72 100644 --- a/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C +++ b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.C @@ -36,6 +36,24 @@ namespace Foam // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +// Estimate dt to cross cell in a few steps +Foam::scalar Foam::streamLineParticle::calcSubCycleDeltaT +( + streamLineParticle::trackData& td, + const scalar dt, + const vector& U +) const +{ + streamLineParticle testParticle(*this); + bool oldKeepParticle = td.keepParticle; + bool oldSwitchProcessor = td.switchProcessor; + scalar fraction = testParticle.trackToFace(position()+dt*U, td); + td.keepParticle = oldKeepParticle; + td.switchProcessor = oldSwitchProcessor; + // Adapt the dt to subdivide the trajectory into 4 substeps. + return dt *fraction/td.nSubCycle_; +} + Foam::vector Foam::streamLineParticle::interpolateFields ( const streamLineParticle::trackData& td, @@ -170,34 +188,56 @@ bool Foam::streamLineParticle::move(streamLineParticle::trackData& td) && lifeTime_ > 0 ) { - // TBD: implement subcycling so step through cells in more than - // one step. - // set the lagrangian time-step scalar dt = min(dtMax, tEnd); - // Store current position and sampled velocity. - --lifeTime_; - sampledPositions_.append(position()); - vector U = interpolateFields(td, position(), cell()); - - if (!td.trackForward_) + // Cross cell in steps + for (label subIter = 0; subIter < td.nSubCycle_; subIter++) { - U = -U; - } + --lifeTime_; - dt *= trackToFace(position()+dt*U, td); + // Store current position and sampled velocity. + sampledPositions_.append(position()); + vector U = interpolateFields(td, position(), cell()); - tEnd -= dt; - stepFraction() = 1.0 - tEnd/deltaT; + if (!td.trackForward_) + { + U = -U; + } - if (tEnd <= ROOTVSMALL) - { - // Force removal - lifeTime_ = 0; + + if (subIter == 0 && td.nSubCycle_ > 1) + { + // Adapt dt to cross cell in a few steps + dt = calcSubCycleDeltaT(td, dt, U); + } + else if (subIter == td.nSubCycle_-1) + { + // Do full step on last subcycle + dt = min(dtMax, tEnd); + } + + + scalar fraction = trackToFace(position()+dt*U, td); + dt *= fraction; + + tEnd -= dt; + stepFraction() = 1.0 - tEnd/deltaT; + + if (tEnd <= ROOTVSMALL) + { + // Force removal + lifeTime_ = 0; + } + + if (!td.keepParticle || td.switchProcessor || lifeTime_ == 0) + { + break; + } } } + if (!td.keepParticle || lifeTime_ == 0) { if (lifeTime_ == 0) diff --git a/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H index d556e4791decf15ab076f885143fe1adb7b3f1d1..bd16038d83cbf29bec5f763bf7154b005563912d 100644 --- a/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H +++ b/src/postProcessing/functionObjects/field/streamLine/streamLineParticle.H @@ -72,6 +72,7 @@ public: const PtrList<interpolationCellPoint<vector> >& vvInterp_; const label UIndex_; const bool trackForward_; + const label nSubCycle_; DynamicList<vectorList>& allPositions_; List<DynamicList<scalarList> >& allScalars_; @@ -87,6 +88,7 @@ public: const PtrList<interpolationCellPoint<vector> >& vvInterp, const label UIndex, const bool trackForward, + const label nSubCycle, DynamicList<List<point> >& allPositions, List<DynamicList<scalarList> >& allScalars, List<DynamicList<vectorList> >& allVectors @@ -97,6 +99,7 @@ public: vvInterp_(vvInterp), UIndex_(UIndex), trackForward_(trackForward), + nSubCycle_(nSubCycle), allPositions_(allPositions), allScalars_(allScalars), allVectors_(allVectors) @@ -123,6 +126,15 @@ private: // Private Member Functions + //- Estimate dt to cross from current face to next one in nSubCycle + // steps. + scalar calcSubCycleDeltaT + ( + streamLineParticle::trackData& td, + const scalar dt, + const vector& U + ) const; + //- Interpolate all quantities; return interpolated velocity. vector interpolateFields ( diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict index c81f8fd5885ea5463ed2cb12e3032fe154880fb1..eed783b8a95f21d2c362180b881e9f8ef612f72f 100644 --- a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict +++ b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict @@ -83,7 +83,10 @@ functions fields (p U k); // Cells particles can travel before being removed - lifeTime 1000; + lifeTime 10000; + + // Number of steps per cell (estimate). Set to 1 to disable subcycling. + nSubCycle 5; // Cloud name to use cloudName particleTracks; diff --git a/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict b/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict index 86cf5ca88a82ecc234f0b72118b4ba84f5590c39..e608ae6e77483c7f15b6135d93f7648c7d6b170d 100644 --- a/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict +++ b/tutorials/incompressible/simpleFoam/pitzDaily/system/controlDict @@ -85,7 +85,10 @@ functions fields (p k U); // Cells particles can travel before being removed - lifeTime 1000; + lifeTime 10000; + + // Number of steps per cell (estimate). Set to 1 to disable subcycling. + nSubCycle 5; // Cloud name to use cloudName particleTracks;