Skip to content

Commit

Permalink
Merge topic 'fix_vtkSOADataArrayTemplate'
Browse files Browse the repository at this point in the history
9d2bd64 vtkSOADataArrayTemplate: fixing GetVoidPointer()

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !9631
  • Loading branch information
acbauer authored and kwrobot committed Oct 21, 2022
2 parents 090dc0d + 9d2bd64 commit f19f976
Show file tree
Hide file tree
Showing 5 changed files with 534 additions and 80 deletions.
1 change: 1 addition & 0 deletions Common/Core/Testing/Cxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ vtk_add_test_cxx(vtkCommonCoreCxxTests tests
TestOStreamWrapper.cxx
TestSMP.cxx
TestSmartPointer.cxx
TestSOADataArray.cxx
TestSortDataArray.cxx
TestSparseArrayValidation.cxx
TestSystemInformation.cxx
Expand Down
249 changes: 249 additions & 0 deletions Common/Core/Testing/Cxx/TestSOADataArray.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*==============================================================================
Program: Visualization Toolkit
Module: TestSOADataArray.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
==============================================================================*/
#include "vtkArrayIterator.h"
#include "vtkArrayIteratorIncludes.h"
#include "vtkMathUtilities.h"
#include "vtkSOADataArrayTemplate.h"

// Needed for portable setenv on MSVC...
#include "vtksys/SystemTools.hxx"

#include <cmath>
#include <limits>
#include <math.h>

namespace
{
const int numValues = 5;
double firstData[numValues] = { 0, 1.5, 2, std::numeric_limits<double>::max(), nan("") };
double secondData[numValues] = { 10, 11.5, 12, std::numeric_limits<double>::infinity(), 15 };
const double voidPointerData[2 * numValues] = { -1, -2.5, std::numeric_limits<double>::infinity(),
-4, -5, -6, std::numeric_limits<double>::min(), -8, nan(""), -10 };
const double otherFirst[numValues] = { voidPointerData[0], voidPointerData[2], voidPointerData[4],
voidPointerData[6], voidPointerData[8] };
const double otherSecond[numValues] = { voidPointerData[1], voidPointerData[3], voidPointerData[5],
voidPointerData[7], voidPointerData[9] };

bool ValuesInfOrNaN(double v1, double v2)
{
return (isinf(v1) && isinf(v2)) || (isnan(v1) && isnan(v2));
}

bool HasCorrectValues(vtkDataArray* array, bool useVoidPointerData)
{
int numberOfComponents = array->GetNumberOfComponents();
const double* first = firstData;
const double* second = secondData;
if (useVoidPointerData)
{
first = numberOfComponents == 1 ? voidPointerData : otherFirst;
second = otherSecond;
}
double* values = static_cast<double*>(array->GetVoidPointer(0));
double tupleValues[2];
for (int i = 0; i < numValues; i++)
{
array->GetTuple(i, tupleValues);
if ((!vtkMathUtilities::NearlyEqual(tupleValues[0], first[i]) &&
!ValuesInfOrNaN(tupleValues[0], first[i])) ||
(numberOfComponents == 2 &&
(!vtkMathUtilities::NearlyEqual(tupleValues[1], second[i]) &&
!ValuesInfOrNaN(tupleValues[1], second[i]))))
{
std::cerr << "Incorrect values returned from GetTypedTuple()\n";
return false;
}
if ((!vtkMathUtilities::NearlyEqual(values[i * numberOfComponents], first[i]) &&
!ValuesInfOrNaN(values[i * numberOfComponents], first[i])) ||
(numberOfComponents == 2 &&
(!vtkMathUtilities::NearlyEqual(values[i * numberOfComponents + 1], second[i]) &&
!ValuesInfOrNaN(values[i * numberOfComponents + 1], second[i]))))
{
std::cerr << "Incorrect values returned from GetVoidPointer()\n";
return false;
}
}

vtkArrayIteratorTemplate<double>* iter = vtkArrayIteratorTemplate<double>::New();
iter->Initialize(array);
for (int i = 0; i < numValues; i++)
{
values = iter->GetTuple(i);
if ((!vtkMathUtilities::NearlyEqual(values[0], first[i]) &&
!ValuesInfOrNaN(values[0], first[i])) ||
(numberOfComponents == 2 &&
(!vtkMathUtilities::NearlyEqual(values[1], second[i]) &&
!ValuesInfOrNaN(values[1], second[i]))))
{
std::cerr << "Incorrect values returned from NewIterator()\n";
return false;
}
}
iter->Delete();

return true;
}
}

int TestSOADataArray(int, char*[])
{
int retVal = 0;
vtkSOADataArrayTemplate<double>* array = vtkSOADataArrayTemplate<double>::New();
array->SetNumberOfComponents(2);
array->SetNumberOfTuples(numValues);
array->SetArray(0, firstData, numValues, false, true);
array->SetArray(1, secondData, numValues, false, true);
if (!HasCorrectValues(array, false))
{
std::cerr << "Setting values through SetArray() failed\n";
retVal++;
}

// now test setting values through vtkArrayIterator
array->Fill(0);
vtkArrayIteratorTemplate<double>* iter = vtkArrayIteratorTemplate<double>::New();
iter->Initialize(array);
for (int i = 0; i < numValues; i++)
{
for (int j = 0; j < 2; j++)
{
double value = (j == 0 ? firstData[i] : secondData[i]);
iter->SetValue(i * 2 + j, value);
}
}
iter->Delete();
if (!HasCorrectValues(array, false))
{
std::cerr << "Setting values through vtkArrayIterator() failed\n";
retVal++;
}

// this should switch to AOS storage
double* ptr = static_cast<double*>(array->GetVoidPointer(0));
std::copy(voidPointerData, voidPointerData + 2 * numValues, ptr);
if (!HasCorrectValues(array, true))
{
std::cerr << "Setting values through GetVoidPointer() failed\n";
retVal++;
}
// now go back to SOA format
array->SetNumberOfComponents(2);
array->SetArray(0, firstData, numValues, false, true);
array->SetArray(1, secondData, numValues, false, true);
if (!HasCorrectValues(array, false))
{
std::cerr << "Setting values through SetArray() failed\n";
retVal++;
}
// now test setting values through vtkArrayIterator
array->Fill(0);
iter = vtkArrayIteratorTemplate<double>::New();
iter->Initialize(array);
for (int i = 0; i < 2 * numValues; i++)
{
iter->SetValue(i, voidPointerData[i]);
}
iter->Delete();
if (!HasCorrectValues(array, true))
{
std::cerr << "Setting values through vtkArrayIterator() failed\n";
retVal++;
}

// now create a new instance from the old (like we would do in a filter)
vtkDataArray* newInstance = array->NewInstance();
newInstance->SetNumberOfComponents(2);
newInstance->SetNumberOfTuples(numValues);
for (vtkIdType i = 0; i < numValues; i++)
{
double tupleValues[2] = { firstData[i], secondData[i] };
newInstance->SetTuple(i, tupleValues);
}
if (!HasCorrectValues(newInstance, false))
{
std::cerr << "Setting values through SetTuple() failed\n";
retVal++;
}
newInstance->Fill(0);
ptr = static_cast<double*>(newInstance->GetVoidPointer(0));
std::copy(voidPointerData, voidPointerData + 2 * numValues, ptr);
if (!HasCorrectValues(newInstance, true))
{
std::cerr << "Setting values through GetVoidPointer() failed\n";
retVal++;
}

// now test the use case of a single component. this is the situation
// where we don't switch between AOS and SOA storage since we don't need to
array->SetNumberOfComponents(1);
array->SetNumberOfTuples(numValues);
array->SetArray(0, firstData, numValues, false, true);
if (!HasCorrectValues(array, false))
{
std::cerr << "Setting single component values through SetArray() failed\n";
retVal++;
}

// now test setting values through vtkArrayIterator
array->Fill(0);
iter = vtkArrayIteratorTemplate<double>::New();
iter->Initialize(array);
for (int i = 0; i < numValues; i++)
{
iter->SetValue(i, firstData[i]);
}
iter->Delete();
if (!HasCorrectValues(array, false))
{
std::cerr << "Setting single component values through vtkArrayIterator() failed\n";
retVal++;
}

ptr = static_cast<double*>(array->GetVoidPointer(0));
std::copy(voidPointerData, voidPointerData + numValues,
ptr); // note that this changes values in firstData
if (!HasCorrectValues(array, true))
{
std::cerr << "Setting single component values through GetVoidPointer() failed\n";
retVal++;
}
// now go back to SOA format
array->SetNumberOfComponents(1);
array->SetArray(0, firstData, numValues, false, true);
if (!HasCorrectValues(array, false))
{
std::cerr << "Setting single component values through SetArray() failed\n";
retVal++;
}
// now test setting values through vtkArrayIterator
array->Fill(0);
iter = vtkArrayIteratorTemplate<double>::New();
iter->Initialize(array);
for (int i = 0; i < numValues; i++)
{
iter->SetValue(i, voidPointerData[i]);
}
iter->Delete();
if (!HasCorrectValues(array, true))
{
std::cerr << "Setting single component values through vtkArrayIterator() failed\n";
retVal++;
}

newInstance->Delete();
array->Delete();

return retVal; // success has retVal = 0
}
10 changes: 1 addition & 9 deletions Common/Core/vtkDataArray.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,7 @@ struct DeepCopyWorker
void operator()(
vtkSOADataArrayTemplate<ValueType>* src, vtkSOADataArrayTemplate<ValueType>* dst) const
{
vtkIdType numTuples = src->GetNumberOfTuples();
for (int comp = 0; comp < src->GetNumberOfComponents(); ++comp)
{
ValueType* srcBegin = src->GetComponentArrayPointer(comp);
ValueType* srcEnd = srcBegin + numTuples;
ValueType* dstBegin = dst->GetComponentArrayPointer(comp);

std::copy(srcBegin, srcEnd, dstBegin);
}
dst->CopyData(src);
}

#ifdef VTK_USE_SCALED_SOA_ARRAYS
Expand Down
Loading

0 comments on commit f19f976

Please sign in to comment.