Change auto seed behavior in PerlinNoise source

The PerlinNoise source has a mode where if a seed is not set, it will
choose a new seed every time it is executed. It did this by using the
value 0 as an indicator to do this (and initializing the Seed to 0).
However, there was a problem with one of the benchmarks that was
specifically setting the seed to 0 and getting unexpected results.

Fix the problem by adding a separate, hidden member of the PerlinNoise
class that keeps track of whether to generate new seeds or not.
This commit is contained in:
Kenneth Moreland 2022-12-06 12:21:04 -07:00
parent d1ec992078
commit 3e7cde8ecb
2 changed files with 30 additions and 25 deletions

@ -128,7 +128,7 @@ struct PerlinNoiseWorklet : public vtkm::worklet::WorkletVisitPointsWithCells
class PerlinNoiseField : public vtkm::filter::FilterField
{
public:
VTKM_CONT PerlinNoiseField(vtkm::IdComponent tableSize, vtkm::Id seed)
VTKM_CONT PerlinNoiseField(vtkm::IdComponent tableSize, vtkm::IdComponent seed)
: TableSize(tableSize)
, Seed(seed)
{
@ -149,26 +149,7 @@ private:
VTKM_CONT void GeneratePermutations()
{
std::mt19937_64 rng;
if (this->Seed != 0)
{
rng.seed(this->Seed);
}
else
{
// If a seed has not been chosen, create a unique seed here. It is done here instead
// of the `PerlinNoise` source constructor for 2 reasons. First, `std::random_device`
// can be slow. If the user wants to specify a seed, it makes no sense to spend
// time generating a random seed only to overwrite it. Second, creating the seed
// here allows subsequent runs of the `PerlinNoise` source to have different random
// results if a seed is not specified.
//
// It is also worth noting that the current time is added to the random number.
// This is because the spec for std::random_device allows it to be deterministic
// if nondeterministic hardware is unavailable and the deterministic numbers can
// be the same for every execution of the program. Adding the current time is
// a fallback for that case.
rng.seed(std::random_device{}() + time(NULL));
}
rng.seed(this->Seed);
std::uniform_int_distribution<vtkm::IdComponent> distribution(0, this->TableSize - 1);
vtkm::cont::ArrayHandle<vtkm::Id> perms;
@ -187,7 +168,7 @@ private:
}
vtkm::IdComponent TableSize;
vtkm::Id Seed;
vtkm::IdComponent Seed;
vtkm::cont::ArrayHandle<vtkm::Id> Permutations;
};
@ -243,7 +224,26 @@ vtkm::cont::DataSet PerlinNoise::DoExecute() const
auto tableSize =
static_cast<vtkm::IdComponent>(vtkm::Max(cellDims[0], vtkm::Max(cellDims[1], cellDims[2])));
PerlinNoiseField noiseGenerator(tableSize, this->Seed);
vtkm::IdComponent seed = this->Seed;
if (!this->SeedSet)
{
// If a seed has not been chosen, create a unique seed here. It is done here instead
// of the `PerlinNoise` source constructor for 2 reasons. First, `std::random_device`
// can be slow. If the user wants to specify a seed, it makes no sense to spend
// time generating a random seed only to overwrite it. Second, creating the seed
// here allows subsequent runs of the `PerlinNoise` source to have different random
// results if a seed is not specified.
//
// It is also worth noting that the current time is added to the random number.
// This is because the spec for std::random_device allows it to be deterministic
// if nondeterministic hardware is unavailable and the deterministic numbers can
// be the same for every execution of the program. Adding the current time is
// a fallback for that case.
seed = static_cast<vtkm::IdComponent>(std::random_device{}() + time(NULL));
}
PerlinNoiseField noiseGenerator(tableSize, seed);
noiseGenerator.SetOutputFieldName("perlinnoise");
dataSet = noiseGenerator.Execute(dataSet);

@ -57,9 +57,13 @@ public:
/// \brief The seed used for the pseudorandom number generation of the noise.
///
/// If the seed is set to 0, then a new, unique seed is picked each time `Execute` is run.
/// If the seed is not set, then a new, unique seed is picked each time `Execute` is run.
VTKM_CONT vtkm::IdComponent GetSeed() const { return this->Seed; }
VTKM_CONT void SetSeed(vtkm::IdComponent seed) { this->Seed = seed; }
VTKM_CONT void SetSeed(vtkm::IdComponent seed)
{
this->Seed = seed;
this->SeedSet = true;
}
private:
vtkm::cont::DataSet DoExecute() const override;
@ -67,6 +71,7 @@ private:
vtkm::Id3 PointDimensions = { 16, 16, 16 };
vtkm::Vec3f Origin = { 0, 0, 0 };
vtkm::IdComponent Seed = 0;
bool SeedSet = false;
};
} //namespace source
} //namespace vtkm