23 const Size offset = *std::max_element(flags1.
begin(), flags1.
end()) + 1;
26 for (
Size& f : flags2) {
41 cat.
connect(
"Add velocity [km/s]",
"velocity", velocity).
setUnits(1.e3_f);
42 cat.
connect(
"Move to COM",
"com", moveToCom)
44 "If true, the particles are moved so that their center of mass lies at the origin and their "
45 "velocities are modified so that the total momentum is zero.");
46 cat.
connect(
"Make flags unique",
"unique_flags", uniqueFlags)
48 "If true, the particle flags of the second input state are renumbered to avoid overlap with "
49 "flags of the first input. This is necessary to properly separate the input bodies.");
62 for (
Size i = 0; i < r.
size(); ++i) {
85 [](
const std::string& name) {
return makeAuto<JoinParticlesJob>(name); },
86 "Simply adds particles from two inputs into a single particle state. Optionally, positions and "
87 "velocities of particles in the second state may be shifted.");
99 cat.
connect(
"eccentricity []",
"e", e);
114 std::accumulate(m1.
begin(), m1.
end(), 0._f) + std::accumulate(m2.begin(), m2.end(), 0._f);
122 for (
Size i = 0; i < r.
size(); ++i) {
140 "particle operators",
141 [](
const std::string& name) {
return makeAuto<OrbitParticlesJob>(name); },
142 "Puts two input bodies on an elliptical trajectory around their common center of gravity. The orbit is "
143 "defined by the semi-major axis and the eccentricity and it lies in the z=0 plane.");
155 defCat.
connect(
"Number of slots",
"slot_cnt", slotCnt);
158 cat.
connect(
"Move to COM",
"com", moveToCom)
160 "If true, the particles are moved so that their center of mass lies at the origin and their "
161 "velocities are modified so that the total momentum is zero.");
162 cat.
connect(
"Make flags unique",
"unique_flags", uniqueFlags)
164 "If true, the particle flags of the states are renumbered to avoid overlap with "
165 "flags of other inputs. This is necessary to properly separate the input bodies.");
172 for (
int i = 1; i < slotCnt; ++i) {
191 "particle operators",
192 [](
const std::string& name) {
return makeAuto<MultiJoinParticlesJob>(name); },
193 "Joins multiple particle sources into a single states.");
205 posCat.
connect(
"Translate [km]",
"offset", positions.offset).
setUnits(1.e3_f);
211 velCat.
connect(
"Add velocity [km/s]",
"velocity_offset", velocities.offset).
setUnits(1.e3_f);
212 velCat.
connect(
"Add spin [rev/day]",
"spin", spin).
setUnits(2._f *
PI / (3600._f * 24._f));
213 velCat.
connect(
"Multiplier",
"velocity_mult", velocities.mult);
219 result = this->getInput<ParticleData>(
"particles");
235 for (
Size i = 0; i < r.
size(); ++i) {
237 r[i] = positionTm * r[i];
240 v[i] = velocityTm * v[i];
244 if (spin !=
Vector(0._f)) {
246 for (
Size i = 0; i < r.
size(); ++i) {
247 v[i] +=
cross(spin, r[i] - r_com);
257 "particle operators",
258 [](
const std::string& name) {
return makeAuto<TransformParticlesJob>(name); },
259 "Modifies positions and velocities of the input particles.");
270 centerCat.
connect(
"Move to CoM",
"positions", centerPositions);
271 centerCat.
connect(
"Set zero momentum",
"velocities", centerVelocities);
277 result = this->getInput<ParticleData>(
"particles");
287 if (centerPositions) {
290 if (centerVelocities) {
300 "particle operators",
301 [](
const std::string& name) {
return makeAuto<CenterParticlesJob>(name); },
302 "Moves particle positions and/or velocities to center-of-mass frame.");
313 "Change material of particles with specific material ID." },
322 cat.
connect(
"Subset",
"subset", type);
347 for (
Size i = 0; i < r.
size(); ++i) {
374 "particle operators",
375 [](
const std::string& name) {
return makeAuto<ChangeMaterialJob>(name); },
376 "Changes the material of all or a subset of the input particles.");
386 "If true, some quantities of the impactor particles are not taken into account when computing the required "
387 "time step. Otherwise, the time step might be unnecessarily too low, as the quantities in the impactor change "
388 "rapidly. Note that this does not affect CFL criterion. It should be always set to false for collisions"
389 "of similar-sized bodies."},
391 "Initial distance of the impactor from the target in units of smoothing length. The impactor should "
392 "not be in contact with the target at the start of the simulation, so the value should be always larger "
393 "than the radius of the selected kernel." },
395 "Relative impact speed (or absolute speed of the impactor if center-of-mass system is set to false) "
396 "in meters per second." },
398 "Impact angle, i.e. angle between normal at the point of impact and the velocity vector of the impactor. "
399 "It can be negative to simulate retrograde impact. The angle is in degrees. "},
401 "If true, colliding bodies are moved to the center-of-mass system, otherwise the target is located "
402 "at origin and has zero velocity." },
414 for (
Size i = 0; i < r.
size(); ++i) {
415 sphere.center() += r[i];
417 sphere.center() /= r.
size();
419 for (
Size i = 0; i < r.
size(); ++i) {
420 sphere.radius() =
max(sphere.radius(),
getLength(r[i] - sphere.center()));
425 static void displace(
Storage& storage,
const Vector& offset) {
427 Vector fixedOffset = offset;
428 fixedOffset[
H] = 0._f;
429 for (
Size i = 0; i < r.
size(); ++i) {
455 Storage target = std::move(this->getInput<ParticleData>(
"target")->storage);
456 Storage impactor = std::move(this->getInput<ParticleData>(
"impactor")->storage);
460 const Sphere targetSphere = getBoundingSphere(target);
461 const Sphere impactorSphere = getBoundingSphere(impactor);
464 displace(target, -targetSphere.
center());
474 const Float x = impactorDistance *
cos(phi) + offset * h;
475 const Float y = impactorDistance *
sin(phi);
476 displace(impactor, -impactorSphere.
center() +
Vector(x, y, 0._f));
480 for (
Size i = 0; i < v.size(); ++i) {
488 const Size flagShift = *std::max_element(targetFlags.
begin(), targetFlags.
end()) + 1;
489 for (
Size i = 0; i < impactorFlags.size(); ++i) {
490 impactorFlags[i] += flagShift;
494 target.
merge(std::move(impactor));
501 result = makeShared<ParticleData>();
508 "particle operators",
509 [](
const std::string& name) {
return makeAuto<CollisionGeometrySetup>(name); },
510 "Adds two input particle states (bodies) into a single state, moving the second body (impactor) to a "
511 "position specified by the impact angle and adding an impact velocity to the impactor.");
521 "Assume equal volume for solid spheres; r_solid = m / (4/3 pi rho_sph)^(1/3)." },
524 "Use a multiple of the smoothing length; r_solid = multiplier * h." },
532 category.
connect(
"Radius",
"radius", type)
533 .
setTooltip(
"Determines how to compute the radii of the solid spheres. Can be one of:\n" +
534 EnumMap::getDesc<HandoffRadius>());
535 category.
connect(
"Radius multiplier",
"radiusMultiplier", radiusMultiplier).
setEnabler([
this] {
546 Storage input = std::move(this->getInput<ParticleData>(
"particles")->storage);
559 for (
Size i = 0; i < r_sphere.size(); ++i) {
562 r_sphere[i][
H] =
cbrt(3._f * m[i] / (4._f *
PI * rho[i]));
565 r_sphere[i][
H] = radiusMultiplier * r_sphere[i][
H];
588 result = makeShared<ParticleData>();
593 "smoothed-to-solid handoff",
595 "particle operators",
596 [](
const std::string& name) {
return makeAuto<SmoothedToSolidHandoff>(name); },
597 "Converts smoothed particles, an output of SPH simulaion, into hard spheres that can be hand off to the "
598 "N-body simulation.");
609 category.
connect(
"Component index",
"index", componentIdx);
610 category.
connect(
"Connectivity factor",
"factor", factor);
611 category.
connect(
"Move to CoM",
"center", center);
616 Storage storage = std::move(this->getInput<ParticleData>(
"particles")->storage);
627 for (
Size i = 0; i < components.
size(); ++i) {
628 if (
int(components[i]) != componentIdx) {
639 result = makeShared<ParticleData>();
646 "particle operators",
647 [](
const std::string& name) {
return makeAuto<ExtractComponentJob>(name); },
648 "Preserves all particles belonging to the largest body in the input particle state (or optionally the "
649 "n-th largest body) and removes all other particles. This modifier is useful to separate the largest "
650 "remnant or the largest fragment in the result of a simulation.");
661 category.
connect(
"Remove damaged",
"damaged.use", removeDamaged);
663 return removeDamaged;
665 category.
connect(
"Remove expanded",
"expanded.use", removeExpanded);
667 return removeExpanded;
673 Storage storage = std::move(this->getInput<ParticleData>(
"particles")->storage);
674 std::set<Size> removeSet;
677 for (
Size i = 0; i < d.
size(); ++i) {
678 if (d[i] >= damageLimit) {
683 if (removeExpanded) {
685 for (
Size i = 0; i < u.
size(); ++i) {
686 if (u[i] >= energyLimit) {
692 std::copy(removeSet.begin(), removeSet.end(), toRemove.
begin());
695 result = makeShared<ParticleData>();
702 "particle operators",
703 [](
const std::string& name) {
return makeAuto<RemoveParticlesJob>(name); },
704 "Removes all particles matching given conditions.");
720 category.
connect(
"Connectivity factor",
"factor", factor);
721 category.
connect(
"Component definition",
"definition", connectivity);
754 for (
Size i = 0; i < m.
size(); ++i) {
755 const Size ci = components[i];
757 rc[ci] += m[i] * r[i];
758 vc[ci] += m[i] * v[i];
762 for (
Size ci = 0; ci < componentCount; ++ci) {
765 rc[ci][
H] =
cbrt(hc[ci]);
773 .getDt<Vector>() = std::move(vc);
782 "particle operators",
783 [](
const std::string& name) {
return makeAuto<MergeComponentsJob>(name); },
784 "Merges all overlapping particles into larger spheres, preserving the total mass and volume of "
785 "particles. Other quantities are handled as intensive, i.e. they are computed using weighted average.");
795 category.
connect(
"Move to CoM",
"center", center);
807 for (
Size i = 0; i < r.
size(); ++i) {
822 "extract particles in domain",
824 "particle operators",
825 [](
const std::string& name) {
return makeAuto<ExtractParticlesInDomainJob>(name); },
826 "Preserves only particles inside the given shape, particles outside the shape are removed.");
836 category.
connect(
"Connectivity factor",
"factor", factor);
842 Storage fragments = std::move(this->getInput<ParticleData>(
"fragments")->storage);
847 Storage original = std::move(this->getInput<ParticleData>(
"original")->storage);
852 if (flags.
size() != components.
size()) {
853 throw InvalidSetup(
"Inputs have different numbers of particles");
856 for (
Size i = 0; i < flags.
size(); ++i) {
857 flags[i] = components[i];
860 result = makeShared<ParticleData>();
865 "emplace components",
867 "particle operators",
868 [](
const std::string& name) {
return makeAuto<EmplaceComponentsAsFlagsJob>(name); },
869 "This modifier detects components (i.e. separated bodies) in the \"fragments\" particle input and stores "
870 "the indices of the components as flags to the other particle input \"original\". This is useful to "
871 "visualize the particles belonging to different fragments in the initial conditions of the simulation.");
882 category.
connect(
"Fraction",
"fraction", fraction);
890 std::set<Size> generated;
892 const Size targetCnt =
clamp(
Size((1._f - fraction) * particleCnt), 0u, particleCnt - 1);
893 while (generated.size() < targetCnt) {
894 generated.insert(
Size(rng() * particleCnt));
897 for (
Size i : generated) {
904 for (
Size i = 0; i < m.
size(); ++i) {
913 "particle operators",
914 [](
const std::string& name) {
return makeAuto<SubsampleJob>(name); },
915 "Preserves a fraction of randomly selected particles, removes the other particles.");
925 "States must have the same number of particles. Compares all quantities of particles at "
926 "corresponding indices. Viable for SPH simulations." },
928 "large_particles_only",
929 "Compares only large particles in the states. The number of particles may be different and the "
930 "indices of particles do not have to match. Viable for N-body simulations with merging." },
941 compareCat.
connect(
"Compare mode",
"compare_mode", mode);
942 compareCat.
connect(
"Tolerance",
"eps", eps);
944 compareCat.
connect(
"Max deviation [km]",
"max_deviation", maxDeviation)
952 Storage& test = this->getInput<ParticleData>(
"test particles")->storage;
953 Storage& ref = this->getInput<ParticleData>(
"reference particles")->storage;
973 "particle operators",
974 [](
const std::string& name) {
return makeAuto<CompareJob>(name); },
975 "Compares two states. If a difference is found, it is shown as an error dialog.");
Various function for interpretation of the results of a simulation.
#define SPH_ASSERT(x,...)
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
uint32_t Size
Integral type used to index arrays (by default).
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Basic interface defining a single run.
Vector moveToCenterOfMassSystem(ArrayView< const Float > m, ArrayView< Vector > r)
Modifies particle positions so that their center of mass lies at the origin.
Generating initial conditions of SPH particles.
VirtualSettings::Category & addGenericCategory(VirtualSettings &connector, std::string &instanceName)
Adds a common settings category, used by all jobs.
Logging routines of the run.
SPH-specific implementation of particle materials.
constexpr INLINE T max(const T &f1, const T &f2)
constexpr INLINE T clamp(const T &f, const T &f1, const T &f2)
INLINE Float cbrt(const Float f)
Returns a cubed root of a value.
constexpr INLINE Float pow< 3 >(const Float v)
constexpr Float DEG_TO_RAD
constexpr Float PI
Mathematical constants.
#define NAMESPACE_SPH_END
const SuccessTag SUCCESS
Global constant for successful outcome.
@ IMPACT_ANGLE
Impact angle in degrees, i.e. angle between velocity vector and normal at the impact point.
@ IMPACT_SPEED
Impact speed in m/s.
HandoffRadius
Determines how to compute the radii of the spheres.
@ EQUAL_VOLUME
The created sphere has the same volume as the SPH particles (=mass/density)
@ SMOOTHING_LENGTH
The radius is proportional to the smoothing length of the particles.
@ FLAG
ID of original body, used to implement discontinuities between bodies in SPH.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ ENERGY
Specific internal energy, always a scalar quantity.
@ DENSITY
Density, always a scalar quantity.
@ MASS
Paricles masses, always a scalar quantity.
Holder of quantity values and their temporal derivatives.
@ SECOND
Quantity with 1st and 2nd derivative.
@ ZERO
Quantity without derivatives, or "zero order" of quantity.
Object representing a three-dimensional sphere.
StaticArray< T0 &, sizeof...(TArgs)+1 > tie(T0 &t0, TArgs &... rest)
Creates a static array from a list of l-value references.
INLINE Float getLength(const Vector &v)
Returns the length of the vector. Enabled only for vectors of floating-point precision.
INLINE BasicVector< float > cross(const BasicVector< float > &v1, const BasicVector< float > &v2)
Cross product between two vectors.
BasicVector< Float > Vector
int main(int argc, char *argv[])
static AffineMatrix scale(const Vector &scaling)
INLINE AffineMatrix & translate(const Vector &t)
static AffineMatrix rotateY(const Float angle)
static AffineMatrix rotateX(const Float angle)
static AffineMatrix rotateZ(const Float angle)
INLINE TCounter size() const
INLINE Iterator< StorageType > begin()
INLINE Iterator< StorageType > end()
void resize(const TCounter newSize)
Resizes the array to new size.
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
void fill(const T &t)
Sets all elements of the array to given value.
void insert(const TCounter position, U &&value)
Inserts a new element to given position in the array.
INLINE TCounter size() const noexcept
INLINE Iterator< StorageType > begin() noexcept
Wrapper of pointer that deletes the resource from destructor.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &UNUSED(callbacks)) override
CollisionGeometrySetup(const std::string &name, const CollisionGeometrySettings &overrides=EMPTY_SETTINGS)
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &UNUSED(callbacks)) override
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
EntryControl & setEnabler(const Enabler &newEnabler)
Adds or replaces the enabler functor of the entry.
EntryControl & setUnits(const Float newMult)
Sets units in which the entry is stored.
EntryControl & setTooltip(const std::string &newTooltip)
Adds or replaces the previous tooltip associanted with the entry.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual bool contains(const Vector &v) const =0
Checks if the given point lies inside the domain.
Base class for all jobs providing particle data.
SharedPtr< ParticleData > result
Data filled by the job when it finishes.
Callbacks executed by the simulation to provide feedback to the user.
virtual void onSetUp(const Storage &storage, Statistics &stats)=0
Called right before the run starts, i.e. after initial conditions are set up.
Thrown when components of the run are mutually incompatible.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
Non-owning wrapper of a material and particles with this material.
INLINE IndexSequence sequence()
Returns iterable index sequence.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
TValue get(const TEnum idx, std::enable_if_t<!std::is_enum< std::decay_t< TValue >>::value, int >=0) const
Returns a value of given type from the settings.
void addEntries(const Settings &settings)
Adds entries from different Settings object into this one, overriding current entries.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &UNUSED(callbacks)) override
INLINE Vector center() const
INLINE Float radius() const
Container storing all quantities used within the simulations.
Size getMaterialCnt() const
Return the number of materials in the storage.
void merge(Storage &&other)
Merges another storage into this object.
Outcome isValid(const Flags< ValidFlag > flags=ValidFlag::COMPLETE) const
Checks whether the storage is in valid state.
void setMaterial(const Size matIdx, const SharedPtr< IMaterial > &material)
Modifies material with given index.
Quantity & insert(const QuantityId key, const OrderEnum order, const TValue &defaultValue)
Creates a quantity in the storage, given its key, value type and order.
StaticArray< Array< TValue > &, 3 > getAll(const QuantityId key)
Retrieves quantity buffers from the storage, given its key and value type.
Array< TValue > & getDt(const QuantityId key)
Retrieves a quantity derivative from the storage, given its key and value type.
void removeAll()
Removes all particles with all quantities (including materials) from the storage.
Size getParticleCnt() const
Returns the number of particles.
@ INDICES_SORTED
Use if the given array is already sorted (optimization)
void remove(ArrayView< const Size > idxs, const Flags< IndicesFlag > flags=EMPTY_FLAGS)
Removes specified particles from the storage.
MaterialView getMaterial(const Size matIdx) const
Returns an object containing a reference to given material.
bool has(const QuantityId key) const
Checks if the storage contains quantity with given key.
Storage clone(const Flags< VisitorEnum > buffers) const
Clones specified buffers of the storage.
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual void evaluate(const RunSettings &global, IRunCallbacks &UNUSED(callbacks)) override
virtual void evaluate(const RunSettings &global, IRunCallbacks &callbacks) override
Runs the operation provided by the job.
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
EntryControl & connect(const std::string &name, const std::string &key, TValue &value)
Connects to given reference.
Holds a map of virtual entries, associated with a unique name.
Category & addCategory(const std::string &name)
Creates a new category of entries.
Creating code components based on values from settings.
const EmptySettingsTag EMPTY_SETTINGS
@ TILLOTSON_SUBLIMATION
Specific sublimation energy.
AutoPtr< IRng > getRng(const RunSettings &settings)
Float trueAnomalyToEccentricAnomaly(const Float v, const Float e)
Computes the eccentric anomaly from the true anomaly and the eccentricity.
Float meanMotion(const Float a, const Float m_total)
Computes the mean motion from the Kepler's 3rd law.
Vector position(const Float a, const Float e, const Float u)
Computes the position on the elliptic trajectory.
Vector velocity(const Float a, const Float e, const Float u, const Float n)
Computes the velocity vector on the elliptic trajectory.
Outcome compareLargeSpheres(const Storage &test, const Storage &ref, const Float fraction, const Float maxDeviation, const Float eps=1.e-6_f)
Compares the positions, velocities and radii of the largest particles in given states.
Outcome compareParticles(const Storage &test, const Storage &ref, const Float eps=1.e-6_f)
Compares particle positions and state quantities of two storages.
@ OVERLAP
Specifies that overlapping particles belong into the same component.
Size findComponents(const Storage &storage, const Float particleRadius, const Flags< ComponentFlag > flags, Array< Size > &indices)
Finds and marks connected components (a.k.a. separated bodies) in the array of vertices.
Vector getCenterOfMass(ArrayView< const Float > m, ArrayView< const Vector > r, ArrayView< const Size > idxs=nullptr)
Computes the center of mass.
Helper class, allowing to register job into the global list of jobs.
Storage storage
Holds all particle positions and other quantities.
Statistics stats
Final statistics of the simulation.
Helper class for adding individual enums to the enum map.