20 return { iter->key, iter->value };
24 return iter == other.iter;
28 return iter != other.iter;
40 return { iter->key, iter->value };
44 return iter == other.iter;
48 return iter != other.iter;
52 : quantities(quantities) {}
63 return quantities.
size();
67 : quantities(quantities) {}
78 return quantities.
size();
85 :
Exception(
"Invalid storage access. " + message) {}
87 static void checkStorageAccess(
const bool result,
const QuantityId id) {
93 static void checkStorageAccess(
const bool result,
const std::string& message) {
103 SPH_ASSERT(from < to || (from == 0 && to == 0));
115 *
this = std::move(other);
119 quantities = std::move(other.quantities);
120 mats = std::move(other.mats);
121 dependent = std::move(other.dependent);
122 userData = std::move(other.userData);
134 template <
typename TValue>
152 checkStorageAccess(
bool(quantity), key);
153 return quantity.
value();
158 checkStorageAccess(
bool(quantity), key);
159 return quantity.
value();
162 template <
typename TValue>
166 return q.
getAll<TValue>();
176 template <
typename TValue>
180 return q.
getAll<TValue>();
190 template <
typename TValue>
204 template <
typename TValue>
206 return const_cast<Storage*
>(
this)->getValue<TValue>(key);
216 template <
typename TValue>
220 return q.
getDt<TValue>();
230 template <
typename TValue>
232 return const_cast<Storage*
>(
this)->getDt<TValue>(key);
242 template <
typename TValue>
246 return q.
getD2t<TValue>();
256 template <
typename TValue>
258 return const_cast<Storage*
>(
this)->getD2t<TValue>(key);
269 template <
typename TValue>
272 if (this->
has(key)) {
275 "Inserting quantity already stored with different type");
282 checkStorageAccess(particleCnt > 0,
"Cannot insert quantity with default value to an empty storage.");
283 quantities.
insert(key,
Quantity(order, defaultValue, particleCnt));
285 return quantities[key];
295 template <
typename TValue>
297 if (this->
has(key)) {
298 checkStorageAccess(values.size() == this->getParticleCnt(),
299 "Size of input array must match number of particles in the storage.");
303 "Inserting quantity already stored with different type");
308 q.
getValue<TValue>() = std::move(values);
314 Quantity q(order, std::move(values));
316 quantities.
insert(key, std::move(q));
318 "Size of input array must match number of particles in the storage.");
329 return quantities[key];
348 const bool retval = checkDependent(*ptr);
363 dependent.
push(other);
368 const MatRange& mat = mats[matId];
378 if (matIdx >= mats.
size()) {
383 mats[matIdx].material = material;
391 const Float value0 = mat0->getParam<
Float>(param);
394 const Float value = mat->getParam<
Float>(param);
395 if (value != value0) {
404 return mats[matIdx].material->range(
id);
407 template <
typename TValue>
425 for (
Size i = 0; i < dependent.
size();) {
427 functor(*storagePtr);
428 storagePtr->propagate(functor);
442 return quantities.
size();
446 if (quantities.
empty()) {
449 return quantities.
begin()->value.size();
457 void Storage::addMissingBuffers(
const Storage& source) {
461 if (!this->
has(element.id)) {
462 quantities.
insert(element.id, element.quantity.createZeros(cnt));
466 if (quantities[element.id].getOrderEnum() < element.quantity.getOrderEnum()) {
467 quantities[element.id].setOrder(element.quantity.getOrderEnum());
473 SPH_ASSERT(!userData && !other.userData,
"Merging storages with user data is currently not supported");
477 *
this = std::move(other);
482 this->addMissingBuffers(other);
483 other.addMissingBuffers(*
this);
489 if (
bool(this->
getMaterialCnt()) !=
bool(other.getMaterialCnt())) {
492 withoutMat->mats.
emplaceBack(makeShared<NullMaterial>(body), 0, other.getParticleCnt());
498 for (MatRange& mat : other.mats) {
510 iteratePair<VisitorEnum::ALL_BUFFERS>(*
this, other, [](
auto& ar1,
auto& ar2) {
511 ar1.pushAll(std::move(ar2));
517 const Size idx0 = idxs[partCnt - 1] + 1;
519 idxs[i] = idx0 + (i - partCnt);
524 this->mats.
pushAll(std::move(other.mats));
528 if (mats[matId].material == mats[matId - 1].material) {
530 mats[matId - 1].to = mats[matId].to;
535 for (
Size i = 0; i <
id.size(); ++i) {
536 if (
id[i] >= matId) {
557 iterate<VisitorEnum::HIGHEST_DERIVATIVES>(*
this, [](
const QuantityId,
auto& dv) {
558 using TValue =
typename std::decay_t<decltype(dv)>::Type;
559 dv.fill(TValue(0._f));
564 SPH_ASSERT(!userData,
"Cloning storages with user data is currently not supported");
566 for (
const auto& q : quantities) {
567 cloned.quantities.
insert(q.key, q.value.clone(buffers));
572 cloned.mats = this->mats.
clone();
581 SPH_ASSERT(!userData,
"Cloning storages with user data is currently not supported");
583 iterate<VisitorEnum::ALL_BUFFERS>(*
this, [newParticleCnt, flags](
auto& buffer) {
585 using Type = typename std::decay_t<decltype(buffer)>::Type;
586 buffer.resizeAndSet(newParticleCnt, Type(0._f));
592 mats[0].to = newParticleCnt;
604 for (
auto i1 = quantities.
begin(), i2 = other.quantities.
begin(); i1 != quantities.
end(); ++i1, ++i2) {
605 i1->value.swap(i2->value, flags);
613 iterate<VisitorEnum::ALL_BUFFERS>(*
this, [cnt, &result, flags](
const auto& buffer) {
615 result = makeFailed(
"One or more buffers have different number of particles:\nExpected: ",
634 return makeFailed(
"MaterialID view not present");
640 "Cached view of MaterialID does not reference the stored quantity. Did you forget to call "
644 for (
Size matId = 0; matId < mats.
size(); ++matId) {
645 const MatRange& mat = mats[matId];
646 for (
Size i = mat.from; i < mat.to; ++i) {
647 if (matIds[i] != matId) {
648 return makeFailed(
"MaterialID of particle does not belong to the material range.\nExpected: ",
654 if ((matId != mats.
size() - 1) && (mat.to != mats[matId + 1].from)) {
655 return makeFailed(
"Material are not stored consecutively.\nLast index: ",
658 mats[matId + 1].from);
661 if (mats[0].from != 0 || mats[mats.
size() - 1].to != cnt) {
662 return makeFailed(
"Materials do not cover all particles.\nFirst: ",
665 mats[mats.
size() - 1].to,
675 SPH_ASSERT(!userData,
"Duplicating particles in storages with user data is currently not supported");
685 std::sort(sortedHolder.
begin(), sortedHolder.
end());
686 sorted = sortedHolder;
695 for (
Size i : sorted) {
696 idxsPerMaterial[matIdsRef[i]].
push(i);
705 const Size matId = matIdsRef[idxs[0]];
706 iterate<VisitorEnum::ALL_BUFFERS>(*
this, [
this, &idxs, matId](
auto& buffer) {
707 using Type =
typename std::decay_t<decltype(buffer)>::Type;
709 for (
Size i : idxs) {
710 Type value = buffer[i];
711 duplicates.
push(value);
713 buffer.insert(mats[matId].to, duplicates.
begin(), duplicates.
end());
716 for (
Size& createdIdx : createdIdxs) {
717 createdIdx += idxs.
size();
719 for (
Size i = 0; i < idxs.size(); ++i) {
720 createdIdxs.push(mats[matId].to + i);
728 std::equal_range(matIdsRef.
begin(), matIdsRef.
end(), matId);
735 for (
Size i = 0; i < sorted.
size(); ++i) {
736 createdIdxs.
push(n0 + i);
738 iterate<VisitorEnum::ALL_BUFFERS>(*
this, [&sorted](
auto& buffer) {
739 using Type =
typename std::decay_t<decltype(buffer)>::Type;
741 for (
Size i : sorted) {
742 Type value = buffer[i];
743 duplicates.
push(value);
745 buffer.pushAll(duplicates.
cbegin(), duplicates.
cend());
752 std::sort(createdIdxs.
begin(), createdIdxs.
end());
757 SPH_ASSERT(!userData,
"Removing particles from storages with user data is currently not supported");
770 std::sort(sortedHolder.
begin(), sortedHolder.
end());
771 sortedIdxs = sortedHolder;
774 iterate<VisitorEnum::ALL_BUFFERS>(*
this, [&sortedIdxs](
auto& buffer) { buffer.remove(sortedIdxs); });
782 for (
Size matId = 0; matId < mats.
size(); ++matId) {
785 if (from != matIds.
end() && *from == matId) {
791 matsToRemove.
push(matId);
794 mats.
remove(matsToRemove);
801 for (
Size matId = 0; matId < mats.
size(); ++matId) {
802 for (
Size i = mats[matId].from; i < mats[matId].to; ++i) {
811 SPH_ASSERT(!userData,
"Removing particles from storages with user data is currently not supported");
816 void Storage::update() {
825 userData = std::move(newData);
835 for (
Size i = 0; i < r.
size(); ++i) {
849 for (
Size i = 0; i < r.
size(); ++i) {
851 r_com += m[i] * r[i];
854 return r_com / m_sum;
857 for (
Size i = 0; i < r.
size(); ++i) {
861 return r_com / r.
size();
868 for (
Size i = 0; i < n; ++i) {
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
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.
Base class for all particle materials.
Functions for iterating over individual quantities in Storage.
ReverseAdapter< TContainer > reverse(TContainer &&container)
#define NAMESPACE_SPH_END
const SuccessTag SUCCESS
Global constant for successful outcome.
INLINE Outcome makeFailed(TArgs &&... args)
Constructs failed object with error message.
Tool to measure time spent in functions and profile the code.
#define MEASURE_SCOPE(name)
QuantityMetadata getMetadata(const QuantityId key)
Returns the quantity information using quantity ID.
QuantityId
Unique IDs of basic quantities of SPH particles.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ MASS
Paricles masses, always a scalar quantity.
@ MATERIAL_ID
Index of material of the particle. Can be generally different than the flag value.
@ ZERO
Quantity without derivatives, or "zero order" of quantity.
StaticArray< T0 &, sizeof...(TArgs)+1 > tie(T0 &t0, TArgs &... rest)
Creates a static array from a list of l-value references.
Vector getCenterOfMass(const Storage &storage)
Returns the center of mass of all particles.
Box getBoundingBox(const Storage &storage, const Float radius)
Convenience function to get the bounding box of all particles.
void setPersistentIndices(Storage &storage)
Adds or updates a quantity holding particle indices to the storage.
Container for storing particle quantities and materials.
INLINE Float distance(const Vector &r, const Vector &axis)
Returns the distance of vector from given axis. The axis is assumed to be normalized.
BasicVector< Float > Vector
INLINE bool empty() const
INLINE TCounter size() const
INLINE Iterator< StorageType > begin()
INLINE Iterator< StorageType > end()
INLINE Iterator< const StorageType > cbegin() const noexcept
void reserve(const TCounter newMaxSize)
Allocates enough memory to store the given number of elements.
INLINE Iterator< StorageType > end() noexcept
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
StorageType & emplaceBack(TArgs &&... args)
Constructs a new element at the end of the array in place, using the provided arguments.
void remove(const TCounter idx)
Removes an element with given index from the array.
INLINE TCounter size() const noexcept
INLINE bool empty() const noexcept
INLINE Iterator< const StorageType > cend() const noexcept
INLINE Iterator< StorageType > begin() noexcept
void pushAll(const TIter first, const TIter last)
Array clone() const
Performs a deep copy of all elements of the array.
Helper class used to allow calling a function only from within T.
Helper object defining three-dimensional interval (box).
INLINE void extend(const Vector &v)
Enlarges the box to contain the vector.
Helper class for iterating over quantities stored in Storage, const version.
bool operator!=(const ConstStorageIterator &other) const
bool operator==(const ConstStorageIterator &other) const
ConstStorageIterator & operator++()
ConstStorageElement operator*()
ConstStorageIterator(const ActIterator iterator, Badge< ConstStorageSequence >)
Helper class, provides functions begin and end, returning const iterators to the first and last quant...
ConstStorageSequence(const FlatMap< QuantityId, Quantity > &quantities, Badge< Storage >)
Size size() const
Returns the number of quantities.
ConstStorageIterator end()
Returns iterator pointing to the one-past-the-end element of the quantity storage.
ConstStorageIterator begin()
Returns iterator pointing to the beginning of the quantity storage.
Wrapper of an integral value providing functions for reading and modifying individual bits.
constexpr INLINE bool has(const TEnum flag) const
Checks if the object has a given flag.
INLINE Iterator< Element > end()
Returns the iterator pointing to the one-past-last element.
INLINE Size empty() const
Returns true if the map contains no elements, false otherwise.
INLINE bool contains(const TKey &key) const
Returns true if the map contains element of given key.
INLINE TValue & insert(const TKey &key, const TValue &value)
Adds a new element into the map or sets new value of element with the same key.
INLINE Iterator< Element > begin()
Returns the iterator pointing to the first element.
INLINE Optional< TValue & > tryGet(const TKey &key)
Returns a reference to the value matching the given key, or NOTHING if no such value exists.
INLINE Size size() const
Returns the number of elements in the map.
Object representing a 1D interval of real numbers.
Exception thrown when accessing missing quantities, casting to different types, etc.
InvalidStorageAccess(const QuantityId id)
Non-owning wrapper of a material and particles with this material.
Wrapper of type value of which may or may not be present.
INLINE Type & value()
Returns the reference to the stored value.
Generic container for storing scalar, vector or tensor quantity and its derivatives.
INLINE Size size() const
Returns the size of the quantity (number of particles)
void setOrder(const OrderEnum order)
OrderEnum getOrderEnum() const
Returns the order of the quantity.
INLINE Array< TValue > & getD2t()
Returns a reference to array of second derivatives of quantity.
StaticArray< Array< TValue > &, 3 > getAll()
Returns all buffers of given type stored in this quantity.
INLINE Array< TValue > & getValue()
Returns a reference to array of quantity values.
INLINE Array< TValue > & getDt()
Returns a reference to array of first derivatives of quantity.
ValueEnum getValueEnum() const
Returns the value order of the quantity.
static const Settings & getDefaults()
\brief Returns a reference to object containing default values of all settings.
Array with fixed number of allocated elements.
Helper class for iterating over quantities stored in Storage.
StorageIterator & operator++()
bool operator!=(const StorageIterator &other) const
StorageIterator(const ActIterator iterator, Badge< StorageSequence >)
StorageElement operator*()
bool operator==(const StorageIterator &other) const
Helper class, provides functions begin and end, returning iterators to the first and last quantity in...
Size size() const
Returns the number of quantities.
StorageSequence(FlatMap< QuantityId, Quantity > &quantities, Badge< Storage >)
StorageIterator end()
Returns iterator pointing to the one-past-the-end element of the quantity storage.
StorageIterator begin()
Returns iterator pointing to the beginning of the quantity storage.
Container storing all quantities used within the simulations.
Size getMaterialCnt() const
Return the number of materials in the storage.
Array< TValue > getMaterialParams(const BodySettingsId param) const
Returns the given material parameter for all materials in the storage.
bool isHomogeneous(const BodySettingsId param) const
Checks if the particles in the storage are homogeneous with respect to given parameter.
void merge(Storage &&other)
Merges another storage into this object.
Quantity & getQuantity(const QuantityId key)
Retrieves quantity with given key from the storage.
void resize(const Size newParticleCnt, const Flags< ResizeFlag > flags=EMPTY_FLAGS)
Changes number of particles for all quantities stored in the storage.
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.
@ COMPLETE
Checks that the storage is complete, i.e. there are no empty buffers.
MaterialView getMaterialOfParticle(const Size particleIdx) const
Returns material view for material of given particle.
bool empty() const
Checks if the storage is empty, i.e. without particles.
void addDependent(const WeakPtr< Storage > &other)
Registers a dependent storage.
StaticArray< Array< TValue > &, 3 > getAll(const QuantityId key)
Retrieves quantity buffers from the storage, given its key and value type.
void swap(Storage &other, const Flags< VisitorEnum > flags)
Swap quantities or given subset of quantities between two storages.
Storage()
Creates a storage with no material.
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.
void setUserData(SharedPtr< IStorageUserData > newData)
Stores new user data into the storage.
Size getParticleCnt() const
Returns the number of particles.
StorageSequence getQuantities()
Returns the sequence of quantities.
Size getQuantityCnt() const
Returns the number of stored quantities.
void propagate(const Function< void(Storage &storage)> &functor)
Executes a given functor recursively for all dependent storages.
Array< Size > duplicate(ArrayView< const Size > idxs, const Flags< IndicesFlag > flags=EMPTY_FLAGS)
Duplicates some particles in the storage.
SharedPtr< IStorageUserData > getUserData() const
Returns the stored user data.
Interval getRange(const QuantityId id, const Size matIdx) const
Returns the bounding range of given quantity.
@ 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.
Storage & operator=(Storage &&other)
Array< TValue > & getD2t(const QuantityId key)
Retrieves a quantity second derivative from the storage, given its key and value type.
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.
@ KEEP_EMPTY_UNCHANGED
Empty buffers will not be resized to new values.
void zeroHighestDerivatives()
Sets all highest-level derivatives of quantities to zero.
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.
Symmetric tensor of 2nd order.
Generic 2nd-order tensor with 9 independent components.
Symmetric traceless 2nd order tensor.
SharedPtr< T > lock() const
Creating code components based on values from settings.
BodySettingsId
Settings of a single body / gas phase / ...
Convert type to ValueType enum.