AGX Dynamics 2.42.1.1
Loading...
Searching...
No Matches
CreateTier.h
Go to the documentation of this file.
1/*
2Copyright 2007-2025. Algoryx Simulation AB.
3
4All AGX source code, intellectual property, documentation, sample code,
5tutorials, scene files and technical white papers, are copyrighted, proprietary
6and confidential material of Algoryx Simulation AB. You may not download, read,
7store, distribute, publish, copy or otherwise disseminate, use or expose this
8material unless having a written signed agreement with Algoryx Simulation AB, or having been
9advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
10valid commercial license from Algoryx Simulation AB.
11
12Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
13from using this software, unless otherwise stated in written agreements with
14Algoryx Simulation AB.
15*/
16
17#ifndef AGX_CREATETIER_H
18#define AGX_CREATETIER_H
19
20#include "Common.h"
21
22namespace agx
23{
24 // Used for temporary storage of new grid tiers.
25 template <typename GridCellTableT>
26 struct GridTier
27 {
29 {
30 }
31
33 GridCellTableT* cellTable;
34 };
35
36 template <typename GridCellTableT>
38 {
39 agxAbort();
40 return 0;
41 }
42
43 template <>
45 {
46 Real halfSize = tierSize * Real(0.5);
47 return std::sqrt(halfSize * halfSize * Real(3)) + halfSize; // Add halfSize to include objects reaching outside cell
48 }
49
50 template <>
52 {
53 Real halfSize = tierSize * Real(0.5);
54 return std::sqrt(halfSize * halfSize * Real(2)) + halfSize; // Add halfSize to include objects reaching outside cell
55 }
56
57 template <typename GridTierDataT, typename GridCellTableT>
59 (
60 size_t tier,
61 Real tierSize,
62 agxData::Buffer *cellIdBuffer,
63 GridTierDataT& gridTier
64 )
65 {
66 gridTier.getStorage()->createInstance();
67 gridTier.size[ tier ] = tierSize;
68 gridTier.invSize[ tier ] = Real(1.0) / tierSize;
69 gridTier.boundingRadius[ tier ] = (Real32)calculateBoundingRadius<GridCellTableT>(tierSize);
70 gridTier.cellTable[ tier ] = new GridCellTableT(cellIdBuffer);
71 gridTier.zoneTable[ tier ] = new ContactZoneTable();
72 // gridTier.zoneDependencyTable[ tier ] = new ZoneDependencyTable();
73 }
74
75 // Align a value to a power of two multiple/fraction of a specified alignment
76 static Real align(Real value, Real alignment)
77 {
78 if (value > alignment)
79 {
80 UInt multiplier = agx::alignPowerOfTwo(UInt(value / alignment));
81 Real alignedSize = alignment * (Real)multiplier;
82 if (alignedSize < value)
83 alignedSize *= 2;
84
85 return alignedSize;
86 }
87 else
88 {
89 return align(value, alignment/2);
90 }
91 }
92
93 template <typename GridTierDataT, typename CellDataT, typename CellT, typename CellIdT, typename CellPosT, typename GridCellTableT, size_t NumNeighbors>
95 (
96 Real minCellSize,
99 GridTierDataT& gridTier,
100 CellDataT& cell,
101 agxData::Array< CellT >& rootCells,
102 const CellIdT *NeighborTable,
103 agx::Bool& hasNewTiers,
105 const agx::UInt& contactZoneAccumulationLevel
106 )
107 {
108 // std::cout << "Creating new tiers for cell size " << minCellSize << ", currently there are " << gridTier.numElements() << " tiers" << std::endl;
109 size_t tier = InvalidIndex;
110 size_t numTiers = gridTier.numElements();
111
112 if ( numTiers == 0 )
113 {
114 if (cell.sizeAlignment > 0)
115 {
116 Real alignedSize = align(minCellSize, cell.sizeAlignment);
117 UInt multiplier = (UInt)round(alignedSize > cell.sizeAlignment ? alignedSize/cell.sizeAlignment : cell.sizeAlignment/alignedSize);
118 agxVerify(agx::isPowerOfTwo(multiplier));
119 // std::cout << "Aligning cell size of initial tier from " << minCellSize << " to " << alignedSize << " (alignment: " << cell.sizeAlignment << ", multiplier " << multiplier << ")" << std::endl;
120 minCellSize = alignedSize;
121 }
122
123 // There are not tiers at all, create a fitting root tier.
124 tier = 0;
125 createTier<GridTierDataT, GridCellTableT>(tier, minCellSize, cell.id.buffer(), gridTier);
126 }
127 else if ( Real(2.0)*minCellSize <= gridTier.size[ numTiers-1 ] )
128 {
129 // There is no tier small enough.
130
131 tier = numTiers - 1; // Make 'tier' point to the currently smallest tier.
132 Real currentTierSize = gridTier.size[ tier ];
133
134 // Create smaller tier(s).
135 while( Real(2.0)*minCellSize <= currentTierSize )
136 {
137 ++tier;
138 currentTierSize = Real(0.5)*gridTier.size[ tier - 1 ];
139 createTier<GridTierDataT, GridCellTableT>(tier, currentTierSize, cell.id.buffer(), gridTier);
140 }
141
142 numTiers = gridTier.numElements();
143 }
144 else if ( minCellSize > gridTier.size[0] )
145 {
146 // There is no tier large enough.
147 Real currentTierSize = gridTier.size[ 0 ];
148
149 // Create proxies for the required new grids in temporary storage.
151 while ( minCellSize > currentTierSize )
152 {
153 currentTierSize *= Real(2.0);
154 // std::cout << " ==> new root tier with size " << currentTierSize << std::endl;
155 newTiers.push_back( GridTier<GridCellTableT>(currentTierSize, nullptr ) );
156 }
157
158 GridCellTableT& rootTierTable = *gridTier.cellTable[0];
159
160 // Allocate slots in the real GridTier storage and make room on the lower indices.
161 size_t numNewTiers = newTiers.size();
162 agxVerify1( numNewTiers > 0, "Expected at least one tier to be created. Why wasn't it?" );
163 gridTier.getStorage()->createInstances( numNewTiers );
164 size_t tierOffset = gridTier.numElements();
165 // std::cout << " creating " << numNewTiers << " tiers, num total " << gridTier.numElements() << std::endl;
166
167 if( numTiers > 0 )
168 {
169 // Move any old tiers down the hierarchy.
170 for ( Int n = (Int)numTiers-1 ; n >= 0 ; --n )
171 {
172 size_t newTierIndex = n + numNewTiers;
173 gridTier.size[ newTierIndex ] = gridTier.size[ n ];
174 gridTier.invSize[ newTierIndex ] = gridTier.invSize[ n ];
175 gridTier.boundingRadius[ newTierIndex ] = gridTier.boundingRadius[ n ];
176 gridTier.cellTable[ newTierIndex ] = gridTier.cellTable[ n ];
177 gridTier.zoneTable[ newTierIndex ] = gridTier.zoneTable[ n ];
178 gridTier.instance[ newTierIndex ].swapId(gridTier.instance[ n ]);
179 }
180 }
181 //numTiers = gridTier.numElements();
182
183 // Copy temporary data into TierGrid storage, write backwards.
184 for ( size_t newTierIndex = 0; newTierIndex < newTiers.size(); ++newTierIndex )
185 {
186 size_t destIndex = numNewTiers - newTierIndex - 1;
187 gridTier.size[ destIndex ] = newTiers[ newTierIndex ].cellSize;
188 gridTier.invSize[ destIndex ] = Real(1.0) / newTiers[ newTierIndex ].cellSize;
189 gridTier.boundingRadius[ destIndex ] = (Real32)calculateBoundingRadius<GridCellTableT>(gridTier.size[ destIndex ]);
190 gridTier.cellTable[ destIndex ] = new GridCellTableT(cell.id.buffer());
191 gridTier.zoneTable[ destIndex ] = new ContactZoneTable();
192
193 }
194
195
196 // Update cell-to-tier references.
197 // std::cout << " Update " << cell.numElements() << " cells" << std::endl;
199 for ( size_t n = 0 ; n < cell.numElements() ; ++n )
200 {
201 // std::cout << n << ": Update tier from " << (UInt)cell.tier[n] << " to " << (UInt)(cell.tier[n]+numNewTiers) << ", size: " << gridTier.size[cell.tier[n] + numNewTiers] << std::endl;
202
203 cell.tier[ n ] = agx::UInt8(cell.tier[n] + numNewTiers);
204
205
212 auto& internalZone = cell.internalZone[n];
213 if (internalZone)
214 {
215 UInt zoneTierOffset = internalZone.tier().calculateIndex() - cell.tier[n];
216
217 if (zoneTierOffset != contactZoneAccumulationLevel) {
218 // std::cout << "Invalidate internal zone for " << cell.id[n] << ", n=" << n << ", internal zone id: " << internalZone.id() << std::endl;
219 invalidatedZones.push_back(internalZone);
220 internalZone.invalidate();
221 }
222 }
223 }
224
225 if (!invalidatedZones.empty()) {
226
227 // Build hash set to avoid duplicate entries
229 for(auto&& zone : emptyZones) {
230 uniqueEmptyZones.insert(zone);
231 }
232
233 auto oldSize = emptyZones.buffer()->size();
234 size_t numNewEmpty = 0;
235 emptyZones.buffer()->resize(oldSize + invalidatedZones.size());
236
237
238 for(auto&& zone : invalidatedZones) {
239 if (!uniqueEmptyZones.contains(zone)) {
240 emptyZones[oldSize + numNewEmpty] = zone;
241 numNewEmpty++;
242 }
243 }
244
245 // Adjusting for duplicates
246 emptyZones.buffer()->resize(oldSize + numNewEmpty);
247 }
248
249
250 // Old root cells need to find their parent
251 for (typename GridCellTableT::iterator it = rootTierTable.begin(); it != rootTierTable.end(); ++it)
252 {
253 UInt32 oldRootCell = *it;
254
255 connectToParentCell<GridTierDataT, CellDataT, CellT, CellIdT, CellPosT, GridCellTableT, NumNeighbors>
256 (
257 deadCells,
258 emptyZones,
259 oldRootCell,
260 cell.tier[ oldRootCell ],
261 cell.id[ oldRootCell ],
262 gridTier, cell,
263 rootCells,
264 NeighborTable,
265 hasNewTiers,
266 solveBodyManager,
267 contactZoneAccumulationLevel
268 );
269 }
270
271 // Store the requested tier, not necessarily tier zero (due to recursive tier construction)
272 tier = gridTier.numElements() - tierOffset;
273 }
274 else
275 {
276 agxAbort1("The appropriate tier for a particle doesn't exist, but the current tier range is neither too large nor too small. Precision problems perhaps?");
277 }
278
279 hasNewTiers = true;
280 return tier;
281 }
282}
283
284
285#endif /* AGX_CREATETIER_H */
Type-specific Array used for fast access into the data held by a Buffer.
Definition: Array.h:107
Abstract representation of a data buffer.
Definition: Buffer.h:56
bool empty() const
Definition: Container.h:136
size_t size() const
Definition: Container.h:134
bool contains(const KeyT &key) const
Boolean query to test existence of an element.
Definition: agx/HashSet.h:314
insert_iterator insert(const KeyT &key)
Insert an element, overwriting if key already exists.
Definition: agx/HashSet.h:250
Inheritance with partial specialization due to bug with ref_ptr containers.
Definition: agx/HashSet.h:670
Templated vector class.
Definition: agx/Vector.h:53
void push_back(const T2 &value)
Definition: agx/Vector.h:715
#define agxVerify1(expr, msg)
Definition: debug.h:132
#define agxVerify(expr)
Definition: debug.h:131
#define agxAbort()
Definition: debug.h:164
#define agxAbort1(msg)
Definition: debug.h:165
#define AGX_FORCE_INLINE
Definition: macros.h:58
The agx namespace contains the dynamics/math part of the AGX Dynamics API.
bool isPowerOfTwo(T value)
Definition: Math.h:408
uint32_t UInt32
Definition: Integer.h:32
agx::HashTable< Vec3i, agx::Physics::HierarchicalGrid::ContactZonePtr > ContactZoneTable
static Real align(Real value, Real alignment)
Definition: CreateTier.h:76
bool Bool
Definition: Integer.h:40
Real calculateBoundingRadius< agx::GridCell2DTable >(Real tierSize)
Definition: CreateTier.h:51
Real calculateBoundingRadius(Real)
Definition: CreateTier.h:37
uint64_t UInt
Definition: Integer.h:27
UInt32 alignPowerOfTwo(UInt32 value)
Definition: Math.h:413
Real calculateBoundingRadius< agx::GridCellTable >(Real tierSize)
Definition: CreateTier.h:44
double Real
Definition: Real.h:41
uint8_t UInt8
Definition: Integer.h:30
float Real32
Definition: Real.h:43
AGXCORE_EXPORT const InvalidIndexStruct InvalidIndex
size_t createMissingTiers(Real minCellSize, agxData::Array< agx::UInt32 > &deadCells, agxData::Array< Physics::HierarchicalGrid::ContactZonePtr > &emptyZones, GridTierDataT &gridTier, CellDataT &cell, agxData::Array< CellT > &rootCells, const CellIdT *NeighborTable, agx::Bool &hasNewTiers, Physics::HierarchicalGrid::SolveBodyManager *solveBodyManager, const agx::UInt &contactZoneAccumulationLevel)
Definition: CreateTier.h:95
int64_t Int
Definition: Integer.h:28
void createTier(size_t tier, Real tierSize, agxData::Buffer *cellIdBuffer, GridTierDataT &gridTier)
Definition: CreateTier.h:59
GridCellTableT * cellTable
Definition: CreateTier.h:33
GridTier(Real cellSize, GridCellTableT *cellTable)
Definition: CreateTier.h:28