Project
Loading...
Searching...
No Matches
SemiregularSpline2D3D.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
17
18#ifndef ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_SEMIREGULARSPLINE2D3D_H
19#define ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_SEMIREGULARSPLINE2D3D_H
20
21#include "GPUCommonDef.h"
22
23#include "RegularSpline1D.h"
24#include "FlatObject.h"
25
26#if !defined(__ROOTCLING__) && !defined(GPUCA_GPUCODE) && !defined(GPUCA_NO_VC)
27#include <Vc/Vc>
28#include <Vc/SimdArray>
29#endif
30
31namespace o2
32{
33namespace gpu
34{
53{
54 public:
56
59
62
65
68
70
72
75
77
78 void cloneFromObject(const SemiregularSpline2D3D& obj, char* newFlatBufferPtr);
79 void destroy();
80
82
84 void moveBufferTo(char* newBufferPtr);
85
87
88 void setActualBufferAddress(char* actualFlatBufferPtr);
89 void setFutureBufferAddress(char* futureFlatBufferPtr);
90
92
95 void construct(const int32_t numberOfRows, const int32_t numbersOfKnots[]);
96
98
104 template <typename T>
105 void correctEdges(T* data) const;
106
108 template <typename T>
109 void getSpline(const T* correctedData, float u, float v, T& x, T& y, T& z) const;
110
113 void getSplineVec(const float* correctedData, float u, float v, float& x, float& y, float& z) const;
114
116 int32_t getNumberOfKnots() const { return mNumberOfKnots; }
117
119 int32_t getNumberOfRows() const { return mNumberOfRows; }
120
122 const RegularSpline1D& getGridV() const { return mGridV; }
123
125 //const RegularSpline1D& getGridV() const { return mGridV; }
126 const RegularSpline1D& getGridU(const int32_t i) const { return getSplineArray()[i]; }
127
129 void getKnotUV(int32_t iKnot, float& u, float& v) const;
130
132 size_t getFlatBufferSize() const { return mFlatBufferSize; }
133
135 int32_t getDataIndex(int32_t i, int32_t j) const;
136 int32_t getDataIndex0(int32_t i, int32_t j) const;
137
139 int32_t getDataIndexMapOffset() const { return mDataIndexMapOffset; }
140
142 const char* getFlatBufferPtr() const { return mFlatBufferPtr; }
143
145 static constexpr size_t getClassAlignmentBytes() { return 8; }
146
148 static constexpr size_t getBufferAlignmentBytes() { return 8; }
149
151 static constexpr size_t getDataAlignmentBytes() { return 8; }
152
153 // Gets the spline array for u-coordinates
155 {
156 return reinterpret_cast<const RegularSpline1D*>(mFlatBufferPtr);
157 }
158
159 const int32_t* getDataIndexMap() const
160 {
161 return reinterpret_cast<const int32_t*>(mFlatBufferPtr + mDataIndexMapOffset);
162 }
163
164 private:
165 void relocateBufferPointers(const char* oldBuffer, char* newBuffer);
166
167 RegularSpline1D* getSplineArrayNonConst()
168 {
169 return reinterpret_cast<RegularSpline1D*>(mFlatBufferPtr);
170 }
171
172 int32_t* getDataIndexMapNonConst()
173 {
174 return reinterpret_cast<int32_t*>(mFlatBufferPtr + mDataIndexMapOffset);
175 }
176
180
181 RegularSpline1D mGridV;
182 int32_t mNumberOfRows;
183 int32_t mNumberOfKnots;
184 int32_t mDataIndexMapOffset;
185
186 ClassDefNV(SemiregularSpline2D3D, 1);
187};
188
192
193inline int32_t SemiregularSpline2D3D::getDataIndex(int32_t u, int32_t v) const
194{
195 return (getDataIndexMap()[v] + u) * 3;
196}
197
198inline int32_t SemiregularSpline2D3D::getDataIndex0(int32_t u, int32_t v) const
199{
200 return (getDataIndexMap()[v] + u);
201}
202
203inline void SemiregularSpline2D3D::getKnotUV(int32_t iKnot, float& u, float& v) const
204{
205
206 // iterate through all RegularSpline1D's
207 for (int32_t i = 0; i < mNumberOfRows; i++) {
208 const RegularSpline1D& gridU = getGridU(i);
209 const int32_t nk = gridU.getNumberOfKnots();
210
211 // if the searched index is less or equal as the number of knots in the current spline
212 // the searched u-v-coordinates have to be in this spline.
213 if (iKnot <= nk - 1) {
214
215 //in that case v is the current index
216 v = mGridV.knotIndexToU(i);
217
218 //and u the coordinate of the given index
219 u = gridU.knotIndexToU(iKnot);
220 break;
221 }
222
223 //if iKnot is greater than number of knots the searched u-v cannot be in the current gridU
224 //so we search for nk less indizes and continue with the next v-coordinate
225 iKnot -= nk;
226 }
227}
228
229template <typename T>
231{
232 //Regular v-Grid (vertical)
233 const RegularSpline1D& gridV = getGridV();
234
235 int32_t nv = mNumberOfRows;
236
237 //EIGENTLICH V VOR U!!!
238 //Wegen Splines aber U vor V
239
240 { // ==== left edge of U ====
241 //loop through all gridUs
242 for (int32_t iv = 1; iv < mNumberOfRows - 1; iv++) {
243 T* f0 = data + getDataIndex(0, iv);
244 T* f1 = f0 + 3;
245 T* f2 = f0 + 6;
246 T* f3 = f0 + 9;
247 for (int32_t idim = 0; idim < 3; idim++) {
248 f0[idim] = (T)(0.5 * f0[idim] + 1.5 * f1[idim] - 1.5 * f2[idim] + 0.5 * f3[idim]);
249 }
250 }
251 }
252
253 { // ==== right edge of U ====
254 //loop through all gridUs
255 for (int32_t iv = 1; iv < mNumberOfRows - 1; iv++) {
256 const RegularSpline1D& gridU = getGridU(iv);
257 int32_t nu = gridU.getNumberOfKnots();
258 T* f0 = data + getDataIndex(nu - 4, iv);
259 T* f1 = f0 + 3;
260 T* f2 = f0 + 6;
261 T* f3 = f0 + 9;
262 for (int32_t idim = 0; idim < 3; idim++) {
263 f3[idim] = (T)(0.5 * f0[idim] - 1.5 * f1[idim] + 1.5 * f2[idim] + 0.5 * f3[idim]);
264 }
265 }
266 }
267
268 { // ==== low edge of V ====
269 const RegularSpline1D& gridU = getGridU(0);
270 int32_t nu = gridU.getNumberOfKnots();
271
272 for (int32_t iu = 0; iu < nu; iu++) {
273 //f0 to f3 are the x,y,z values of 4 points in the grid along the v axis.
274 //Since there are no knots because of the irregularity you can get this by using the getSplineMethod.
275 T* f0 = data + getDataIndex(iu, 0);
276 float u = gridU.knotIndexToU(iu);
277
278 float x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0, x3 = 0, y3 = 0, z3 = 0;
279 getSpline(data, u, gridV.knotIndexToU(1), x1, y1, z1);
280 getSpline(data, u, gridV.knotIndexToU(2), x2, y2, z2);
281 getSpline(data, u, gridV.knotIndexToU(3), x3, y3, z3);
282
283 T f1[3] = {x1, y1, z1};
284 T f2[3] = {x2, y2, z2};
285 T f3[3] = {x3, y3, z3};
286 for (int32_t idim = 0; idim < 3; idim++) {
287 f0[idim] = (T)(0.5 * f0[idim] + 1.5 * f1[idim] - 1.5 * f2[idim] + 0.5 * f3[idim]);
288 }
289 }
290 }
291
292 { // ==== high edge of V ====
293 int32_t nu = getGridU(nv - 1).getNumberOfKnots();
294
295 for (int32_t iu = 0; iu < nu; iu++) {
296
297 float u = getGridU(nv - 1).knotIndexToU(iu);
298
299 float x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0, x3 = 0, y3 = 0, z3 = 0;
300 getSpline(data, u, gridV.knotIndexToU(nv - 4), x1, y1, z1);
301 getSpline(data, u, gridV.knotIndexToU(nv - 3), x2, y2, z2);
302 getSpline(data, u, gridV.knotIndexToU(nv - 2), x3, y3, z3);
303
304 T f0[3] = {x1, y1, z1};
305 T f1[3] = {x2, y2, z2};
306 T f2[3] = {x3, y3, z3};
307 T* f3 = data + getDataIndex(iu, nv - 1);
308 for (int32_t idim = 0; idim < 3; idim++) {
309 f3[idim] = (T)(0.5 * f0[idim] - 1.5 * f1[idim] + 1.5 * f2[idim] + 0.5 * f3[idim]);
310 }
311 }
312 }
313
314 // =============== CORRECT CORNERS ==============
315
316 { // === Lower left corner with u-direction ===
317 T* f0 = data;
318 T* f1 = f0 + 3;
319 T* f2 = f0 + 6;
320 T* f3 = f0 + 9;
321 for (int32_t idim = 0; idim < 3; idim++) {
322 f0[idim] = (T)(0.5 * f0[idim] + 1.5 * f1[idim] - 1.5 * f2[idim] + 0.5 * f3[idim]);
323 }
324 }
325
326 { // ==== Lower right corner with u-direction ===
327
328 const RegularSpline1D& gridU = getGridU(0);
329 int32_t nu = gridU.getNumberOfKnots();
330 T* f0 = data + getDataIndex(nu - 4, 0);
331 T* f1 = f0 + 3;
332 T* f2 = f0 + 6;
333 T* f3 = f0 + 9;
334 for (int32_t idim = 0; idim < 3; idim++) {
335 f3[idim] = (T)(0.5 * f0[idim] - 1.5 * f1[idim] + 1.5 * f2[idim] + 0.5 * f3[idim]);
336 }
337 }
338
339 { // === upper left corner with u-direction ===
340 T* f0 = data + getDataIndex(0, nv - 1);
341 T* f1 = f0 + 3;
342 T* f2 = f0 + 6;
343 T* f3 = f0 + 9;
344 for (int32_t idim = 0; idim < 3; idim++) {
345 f0[idim] = (T)(0.5 * f0[idim] + 1.5 * f1[idim] - 1.5 * f2[idim] + 0.5 * f3[idim]);
346 }
347 }
348
349 { // ==== upper right corner with u-direction ===
350 const RegularSpline1D& gridU = getGridU(nv - 1);
351 int32_t nu = gridU.getNumberOfKnots();
352 T* f0 = data + getDataIndex(nu - 4, nv - 1);
353 T* f1 = f0 + 3;
354 T* f2 = f0 + 6;
355 T* f3 = f0 + 9;
356 for (int32_t idim = 0; idim < 3; idim++) {
357 f3[idim] = (T)(0.5 * f0[idim] - 1.5 * f1[idim] + 1.5 * f2[idim] + 0.5 * f3[idim]);
358 }
359 }
360}
361
362template <typename T>
363inline void SemiregularSpline2D3D::getSpline(const T* correctedData, float u, float v, T& x, T& y, T& z) const
364{
365 // Get interpolated value for f(u,v) using data array correctedData[getNumberOfKnots()] with corrected edges
366
367 // find the v indizes of the u-splines that are needed.
368 int32_t iknotv = mGridV.getKnotIndex(v);
369
370 // to save the index positions of u-coordinates we create an array
371 T dataVx[12];
372 // int32_t dataOffset0 = getDataIndex0(0, iknotv-1); //index of the very left point in the vi-1-th gridU
373
374 // we loop through the 4 needed u-Splines
375 int32_t vxIndex = 0;
376 for (int32_t vi = 0; vi < 4; vi++, vxIndex += 3) {
377
378 const int32_t vDelta = iknotv + vi - 1;
379 const RegularSpline1D& gridU = getGridU(vDelta);
380 // and find at which index in that specific spline the u-coordinate must lay.
381
382 const int32_t ui = gridU.getKnotIndex(u);
383 const int32_t dataOffset = getDataIndex(ui - 1, vDelta); //(dataOffset0 + (ui-1))*3;
384
385 dataVx[vxIndex + 0] = gridU.getSpline(ui, correctedData[dataOffset], correctedData[dataOffset + 3], correctedData[dataOffset + 6], correctedData[dataOffset + 9], u);
386 dataVx[vxIndex + 1] = gridU.getSpline(ui, correctedData[dataOffset + 1], correctedData[dataOffset + 4], correctedData[dataOffset + 7], correctedData[dataOffset + 10], u);
387 dataVx[vxIndex + 2] = gridU.getSpline(ui, correctedData[dataOffset + 2], correctedData[dataOffset + 5], correctedData[dataOffset + 8], correctedData[dataOffset + 11], u);
388 }
389
390 //return results
391 x = mGridV.getSpline(iknotv, dataVx[0], dataVx[3], dataVx[6], dataVx[9], v);
392 y = mGridV.getSpline(iknotv, dataVx[1], dataVx[4], dataVx[7], dataVx[10], v);
393 z = mGridV.getSpline(iknotv, dataVx[2], dataVx[5], dataVx[8], dataVx[11], v);
394}
395
396inline void SemiregularSpline2D3D::getSplineVec(const float* correctedData, float u, float v, float& x, float& y, float& z) const
397{
398 // Same as getSpline, but using vectorized calculation.
399 // \param correctedData should be at least 128-bit aligned
400
401#if !defined(__ROOTCLING__) && !defined(GPUCA_GPUCODE) && !defined(GPUCA_NO_VC)
402 //&& !defined(__CLING__)
403 /*
404 Idea: There are 16 knots important for (u, v).
405 a,b,c,d := Knots in first u-grid
406 e,f,g,h := Knots in second u-grid
407 i,j,k,l := Knots in third u-grid
408 m,n,o,p := Knots in fourth u-grid.
409 It could be possible to calculate the spline in 3 dimentions for a,b,c,d at the same time as e,f,g,h etc.
410 3 of the 4 parallel threads of the vector would calculate x,y,z for one row and the last task already calculates x for the next one.
411 => 4x faster
412
413 Problem:To do this, we need vectors where every i-th element is used for the calculation. So what we need is:
414 [a,e,i,m]
415 [b,f,j,n]
416 [c,g,k,o]
417 [d,h,l,p]
418 This is barely possible to do with a good performance because e.g. a,e,i,m do not lay beside each other in data.
419
420 Work around 1:
421 Don't calculate knots parrallel but the dimensions. But you can only be 3x faster this way because the 4th thread would be the x-dimension of the next point.
422
423 Work around 2:
424 Try to create a matrix as it was mentioned earlier ([a,e,i,m][b,f,..]...) by copying data.
425 This may be less efficient than Work around 1 but needs to be measured.
426
427 */
428
429 //workaround 1:
430 int32_t vGridi = mGridV.getKnotIndex(v);
431
432 float dataU[12];
433 int32_t vOffset = 0;
434 for (int32_t vi = 0; vi < 4; vi++, vOffset += 3) {
435 const RegularSpline1D& gridU = getGridU(vi + vGridi - 1);
436
437 // and find at which index in that specific spline the u-coordinate must lay.
438 int32_t ui = gridU.getKnotIndex(u);
439
440 // using getDataIndex we know at which position knot (ui, vi) is saved.
441 // dataU0 to U3 are 4 points along the u-spline surrounding the u coordinate.
442 const float* dataU0 = correctedData + getDataIndex(ui - 1, vGridi + vi - 1);
443
444 Vc::float_v dt0(dataU0 + 0);
445 Vc::float_v dt1(dataU0 + 3);
446 Vc::float_v dt2(dataU0 + 6);
447 Vc::float_v dt3(dataU0 + 9);
448
449 Vc::float_v resU = gridU.getSpline(ui, dt0, dt1, dt2, dt3, u);
450
451 // save the results in dataVx array
452 dataU[vOffset + 0] = resU[0];
453 dataU[vOffset + 1] = resU[1];
454 dataU[vOffset + 2] = resU[2];
455 }
456
457 Vc::float_v dataV0(dataU + 0);
458 Vc::float_v dataV1(dataU + 3);
459 Vc::float_v dataV2(dataU + 6);
460 Vc::float_v dataV3(dataU + 9);
461
462 Vc::float_v res = mGridV.getSpline(vGridi, dataV0, dataV1, dataV2, dataV3, v);
463 x = res[0];
464 y = res[1];
465 z = res[2];
466
467//getSpline( correctedData, u, v, x, y, z );
468#else
469 getSpline(correctedData, u, v, x, y, z);
470#endif
471}
472} // namespace gpu
473} // namespace o2
474
475#endif
Definition of FlatObject class.
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
Definition of IrregularSpline1D class.
GPUCA_GPUCODE.
Definition FlatObject.h:176
char * releaseInternalBuffer()
_____________ Methods for making the data buffer external __________________________
Definition FlatObject.h:526
int32_t mFlatBufferSize
size of the flat buffer
Definition FlatObject.h:322
static constexpr size_t getBufferAlignmentBytes()
Gives minimal alignment in bytes required for the flat buffer.
Definition FlatObject.h:197
static constexpr size_t getClassAlignmentBytes()
_____________ Memory alignment __________________________
Definition FlatObject.h:194
T getSpline(const int32_t iknot, T f0, T f1, T f2, T f3, float u) const
Get interpolated value for f(u) using spline at knot "knot_1" and function values at knots {knot_0,...
int32_t getKnotIndex(float u) const
int32_t getNumberOfKnots() const
Get number of knots.
double knotIndexToU(int32_t index) const
Get the U-Coordinate depending on the given knot-Index.
const RegularSpline1D & getGridV() const
Get 1-D grid for U coordinate.
void setFutureBufferAddress(char *futureFlatBufferPtr)
SemiregularSpline2D3D(const SemiregularSpline2D3D &)=delete
Copy constructor: disabled to avoid ambiguity. Use cloneFromObject() instead.
void cloneFromObject(const SemiregularSpline2D3D &obj, char *newFlatBufferPtr)
Construction interface.
int32_t getNumberOfKnots() const
Get number total of knots: UxV.
const RegularSpline1D * getSplineArray() const
void getSplineVec(const float *correctedData, float u, float v, float &x, float &y, float &z) const
int32_t getDataIndex(int32_t i, int32_t j) const
Gets the knot index which is the i-th knot in v-space and the j-th knot in u-space.
const int32_t * getDataIndexMap() const
~SemiregularSpline2D3D()=default
Destructor.
int32_t getNumberOfRows() const
Get number of rows. Always the same as gridV's number of knots.
void construct(const int32_t numberOfRows, const int32_t numbersOfKnots[])
_______________ Construction interface ________________________
void getKnotUV(int32_t iKnot, float &u, float &v) const
Get u,v of i-th knot.
int32_t getDataIndex0(int32_t i, int32_t j) const
void getSpline(const T *correctedData, float u, float v, T &x, T &y, T &z) const
Get interpolated value for f(u,v) using data array correctedData[getNumberOfKnots()] with corrected e...
size_t getFlatBufferSize() const
Get size of the mFlatBuffer data.
int32_t getDataIndexMapOffset() const
Gets the offset for the data index map inside the flat buffer.
static constexpr size_t getClassAlignmentBytes()
Get minimal required alignment for the class.
static constexpr size_t getBufferAlignmentBytes()
Get minimal required alignment for the flat buffer.
const RegularSpline1D & getGridU(const int32_t i) const
Get 1-D grid for V coordinate.
void setActualBufferAddress(char *actualFlatBufferPtr)
Moving the class with its external buffer to another location.
void correctEdges(T *data) const
_______________ Main functionality ________________________
SemiregularSpline2D3D & operator=(const SemiregularSpline2D3D &)=delete
Assignment operator: disabled to avoid ambiguity. Use cloneFromObject() instead.
SemiregularSpline2D3D()
_____________ Constructors / destructors __________________________
const char * getFlatBufferPtr() const
Get pointer to the flat buffer.
static constexpr size_t getDataAlignmentBytes()
Get minimal required alignment for the spline data.
void moveBufferTo(char *newBufferPtr)
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
const GLdouble * v
Definition glcorearb.h:832
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLboolean * data
Definition glcorearb.h:298
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...