diff --git a/TurTLE/test/particle_set/ADNS.py b/TurTLE/test/particle_set/ADNS.py index 1c6a66a9ae2a1628994311cff1256f3096959a01..8e60c82b5cb675301a4b79ef38f1b35ec2c0ceb9 100644 --- a/TurTLE/test/particle_set/ADNS.py +++ b/TurTLE/test/particle_set/ADNS.py @@ -81,7 +81,7 @@ class ADNS(TurTLE.DNS): self.parameters['niter_stat'] = int(20) self.parameters['niter_out'] = int(200) self.parameters['checkpoints_per_file'] = int(1) - self.parameters['dt'] = float(0.001) + self.parameters['dt'] = float(0.0001) self.parameters['histogram_bins'] = int(64) self.parameters['max_velocity_estimate'] = float(1) self.parameters['max_vorticity_estimate'] = float(1) diff --git a/cpp/particles/abstract_particle_rhs.hpp b/cpp/particles/abstract_particle_rhs.hpp index 3687997809c041c16ca2243f2d9f624c3b79400c..a948a5effd9bf22b1b9534e150dfde01d08fa2e0 100644 --- a/cpp/particles/abstract_particle_rhs.hpp +++ b/cpp/particles/abstract_particle_rhs.hpp @@ -38,10 +38,13 @@ class abstract_particle_rhs virtual ~abstract_particle_rhs(){} // important bit + // may resort particles, therefore it takes the + // parameter `additional_data` to possibly resort other arrays virtual int operator()( double t, abstract_particle_set &pset, - particle_rnumber *result) const = 0; + particle_rnumber *result, + std::vector<std::unique_ptr<abstract_particle_set::particle_rnumber[]>> &additional_data) const = 0; // for post-timestep actions such as // normalization of orientation vector diff --git a/cpp/particles/particle_solver.cpp b/cpp/particles/particle_solver.cpp index d817079160a1c369cb819f779d5d869aa21210bf..65ec05704c8be78f2b4a2de7643a9832ed831638 100644 --- a/cpp/particles/particle_solver.cpp +++ b/cpp/particles/particle_solver.cpp @@ -34,9 +34,11 @@ int particle_solver::Euler( auto *rhs_val = new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]; // temporary array for new particle state auto *xx = new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]; + // empty array required by rhs call + std::vector<std::unique_ptr<particle_rnumber[]>> tvalues; // compute right hand side - rhs(0, *(this->pset), rhs_val); + rhs(0, *(this->pset), rhs_val, tvalues); // compute new particle state @@ -50,9 +52,7 @@ int particle_solver::Euler( //std::vector<std::unique_ptr<particle_rnumber[]>> temporary; this->pset->setParticleState(xx); - // fake kvalues for use in redistribute - std::vector<std::unique_ptr<particle_rnumber[]>> kvalues; - this->pset->redistribute(kvalues); + this->pset->redistribute(tvalues); // ensure new state is consistent with physical model rhs.imposeModelConstraints(*(this->pset)); @@ -86,57 +86,65 @@ int particle_solver::Heun( { TIMEZONE("particle_solver::Euler"); // temporary arrays for storing the two right-hand-side values - // I allocate 3 values, because 0 will be used for the initial condition // We need to be able to redistribute the initial condition for computations to make sense, // so we must put everything in the same vector. - std::vector<std::unique_ptr<particle_rnumber[]>> kvalues; - kvalues.resize(3); + std::vector<std::unique_ptr<particle_rnumber[]>> tvalues; + std::unique_ptr<particle_rnumber[]> xx, x0, k1, k2; // allocate k0 - kvalues[0].reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); + x0.reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); // allocate k1 - kvalues[1].reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); + k1.reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); // allocate k2 - kvalues[2].reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); - // temporary array for particle states - std::unique_ptr<particle_rnumber[]> xx; + k2.reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); + // allocate xx xx.reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); // store initial condition - this->pset->getParticleState(kvalues[0].get()); + this->pset->getParticleState(x0.get()); + tvalues.resize(1); + tvalues[0].reset(new particle_rnumber[1]); + tvalues[0].swap(x0); // compute k1 - rhs(0, *(this->pset), kvalues[1].get()); + rhs(0, *(this->pset), k1.get(), tvalues); + x0.swap(tvalues[0]); // compute xn+h*k1 in particle set this->pset->LOOP( [&](const partsize_t idx){ - xx[idx] = kvalues[0][idx] + dt*kvalues[1][idx]; + xx[idx] = x0[idx] + dt*k1[idx]; }); // copy the temporary state to the particle set, and redistribute // we MUST redistribute, because we want to interpolate. - // we MUST shuffle kvalues according to the same redistribution, otherwise + // we MUST shuffle values according to the same redistribution, otherwise // the subsequent computations are meaningless (and can lead to segfaults). this->pset->setParticleState(xx.get()); - this->pset->redistribute(kvalues); + tvalues.resize(2); + tvalues[0].reset(new particle_rnumber[1]); + tvalues[1].reset(new particle_rnumber[1]); + tvalues[0].swap(x0); + tvalues[1].swap(k1); + this->pset->redistribute(tvalues); // impose model constraints, so that rhs is computed correctly rhs.imposeModelConstraints(*(this->pset)); // compute k2 // note the temporal interpolation is at `1`, i.e. end of time-step - rhs(1, *(this->pset), kvalues[2].get()); + rhs(1, *(this->pset), k2.get(), tvalues); + x0.swap(tvalues[0]); + k1.swap(tvalues[1]); + // tvalues no longer required + tvalues.resize(0); // local number of particles may have changed xx.reset(new particle_rnumber[this->pset->getLocalNumberOfParticles()*(this->pset->getStateSize())]); // compute final state this->pset->LOOP( [&](const partsize_t idx){ - xx[idx] = kvalues[0][idx] + 0.5*dt*(kvalues[1][idx] + kvalues[2][idx]); + xx[idx] = x0[idx] + 0.5*dt*(k1[idx] + k2[idx]); }); this->pset->setParticleState(xx.get()); - // kvalues no longer required, no point in passing them around with MPI - kvalues.resize(0); // redistribute, impose model constraints - this->pset->redistribute(kvalues); - DEBUG_MSG("check 03\n"); + this->pset->redistribute(tvalues); rhs.imposeModelConstraints(*(this->pset)); // and we are done diff --git a/cpp/particles/rhs/tracer_rhs.hpp b/cpp/particles/rhs/tracer_rhs.hpp index 676789ae1ad5ffdcce91d13d2e456fadcce591e0..50da9e90ac7c5f48b2a28b62efd0219de674add6 100644 --- a/cpp/particles/rhs/tracer_rhs.hpp +++ b/cpp/particles/rhs/tracer_rhs.hpp @@ -52,7 +52,8 @@ class tracer_rhs: public abstract_particle_rhs int operator()( double t, abstract_particle_set &pset, - particle_rnumber *result) const + particle_rnumber *result, + std::vector<std::unique_ptr<abstract_particle_set::particle_rnumber[]>> &additional_data) const { // interpolation adds on top of existing values, so result must be cleared. std::fill_n(result, pset.getLocalNumberOfParticles()*3, 0); diff --git a/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp b/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp index a21a8113b551f2f08927765977ed2c3d8337b341..200fcdeb80c5bbe39568264b83b7c2591d4076f5 100644 --- a/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp +++ b/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp @@ -47,29 +47,31 @@ class tracer_with_collision_counter_rhs: public tracer_rhs<rnumber, be, tt> int operator()( double t, abstract_particle_set &pset, - abstract_particle_set::particle_rnumber *result) const + abstract_particle_set::particle_rnumber *result, + std::vector<std::unique_ptr<abstract_particle_set::particle_rnumber[]>> &additional_data) const { // interpolation adds on top of existing values, so result must be cleared. std::fill_n(result, pset.getLocalNumberOfParticles()*3, 0); int interpolation_result = (*(this->velocity))(t, pset, result); - std::vector<std::unique_ptr<abstract_particle_set::particle_rnumber[]>> bla; - bla.resize(1); - bla[0].reset(new abstract_particle_set::particle_rnumber[pset.getLocalNumberOfParticles()*pset.getStateSize()]); + additional_data.push_back(std::unique_ptr<abstract_particle_set::particle_rnumber[]>( + new abstract_particle_set::particle_rnumber[pset.getLocalNumberOfParticles()*pset.getStateSize()])); // copy rhs values to temporary array pset.LOOP( [&](const abstract_particle_set::partsize_t idx) { - bla[0][idx] = result[idx]; + additional_data[additional_data.size()-1][idx] = result[idx]; }); pset.template applyP2PKernel<3, p2p_ghost_collisions<abstract_particle_set::particle_rnumber, abstract_particle_set::partsize_t>>( this->p2p_gc, - bla); + additional_data); // copy shuffled rhs values pset.LOOP( [&](const abstract_particle_set::partsize_t idx) { - result[idx] = bla[0][idx]; + result[idx] = additional_data[additional_data.size()-1][idx]; }); + // clear temporary array + additional_data.pop_back(); return interpolation_result; }