Skip to content

Commit

Permalink
support merging particle sets based on 2 different attributes
Browse files Browse the repository at this point in the history
Previously, you could merge particle sets and override a particle
when the value of a specified attribute (typ. 'ids') was identical.  Because
ids can sometimes be unintentionally duplicated, an additional attribute
can be specified when performing the matching.  When used, a particle is
overridden only when the values of both attributes are identical.

toward: LOOK-1965 Duplicate particle IDs in baked aurora xgenAuroraFiles
  • Loading branch information
Lawrence Chai committed Oct 12, 2021
1 parent 412a481 commit b2b1305
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 20 deletions.
Binary file added src/data/baseidsfaceid.bgeo
Binary file not shown.
Binary file added src/data/deltaids.bgeo
Binary file not shown.
Binary file added src/data/deltaidsfaceid.bgeo
Binary file not shown.
2 changes: 1 addition & 1 deletion src/lib/Partio.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ ParticlesDataMutable* computeClustering(ParticlesDataMutable* particles, const i
provided or the particle's attribute value is not found in the base set,
a new particle is added. If used, the identifier must be a single INT.
*/
void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier=std::string());
void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier0=std::string(), const std::string& identifier1=std::string());

}
#endif
55 changes: 37 additions & 18 deletions src/lib/core/Particle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,31 +445,48 @@ struct AttributePair {
T delta;
};

void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier)
// Combines two hashes.
inline uint32_t hashCombine(uint32_t hashPriorCombine, uint32_t b)
{
// Following http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
// The constants are somewhat arbitrary, and others may work equally well.
// Further explanation here: http://stackoverflow.com/a/4948967
return hashPriorCombine ^ (0x9e3779b9U + (hashPriorCombine << 6) + (hashPriorCombine >> 2) + b);
}

struct IntPairHash {
size_t operator()(std::pair<int, int> v) const
{
return hashCombine(v.first, v.second);
}
};

void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier0, const std::string& identifier1)
{
// Build a map from the identifier value to the particle index
// and locate the identifier attribute in the base.
// This assumes unique identifiers per particle.
std::unordered_map<int,int> idToParticleIndex;
ParticleAttribute baseIdAttr;
bool baseHasIdentifier = base.attributeInfo(identifier.c_str(), baseIdAttr);
if (baseHasIdentifier) {
if (baseIdAttr.type == INT) {
for (int i=0; i<base.numParticles(); i++) {
idToParticleIndex[base.data<int>(baseIdAttr,i)[0]] = i;
}
} else {
baseHasIdentifier = false;
std::unordered_map<std::pair<int,int>,int,IntPairHash> idToParticleIndex;
ParticleAttribute baseIdAttr0;
bool baseHasIdentifier0 = base.attributeInfo(identifier0.c_str(), baseIdAttr0);
baseHasIdentifier0 = baseHasIdentifier0 ? baseIdAttr0.type == INT : false;
ParticleAttribute baseIdAttr1;
bool baseHasIdentifier1 = base.attributeInfo(identifier1.c_str(), baseIdAttr1);
baseHasIdentifier1 = baseHasIdentifier1 ? baseIdAttr1.type == INT : false;
if (baseHasIdentifier0 || baseHasIdentifier1) {
for (int i=0; i<base.numParticles(); i++) {
idToParticleIndex[std::make_pair(baseHasIdentifier0 ? base.data<int>(baseIdAttr0,i)[0] : 0,
baseHasIdentifier1 ? base.data<int>(baseIdAttr1,i)[0] : 0)] = i;
}
}

// Locate the identifier attribute in the delta
ParticleAttribute deltaIdAttr;
bool deltaHasIdentifier = delta.attributeInfo(identifier.c_str(), deltaIdAttr);
if (deltaHasIdentifier) {
deltaHasIdentifier &= deltaIdAttr.type == INT;
}
bool hasIdentifier = baseHasIdentifier && deltaHasIdentifier;
ParticleAttribute deltaIdAttr0;
bool deltaHasIdentifier0 = delta.attributeInfo(identifier0.c_str(), deltaIdAttr0);
deltaHasIdentifier0 = deltaHasIdentifier0 ? deltaIdAttr0.type == INT : false;
ParticleAttribute deltaIdAttr1;
bool deltaHasIdentifier1 = delta.attributeInfo(identifier1.c_str(), deltaIdAttr1);
deltaHasIdentifier1 = deltaHasIdentifier1 ? deltaIdAttr1.type == INT : false;

// Identify the attributes to be copied (base present in delta)
std::vector<AttributePair<ParticleAttribute>> attrs;
Expand Down Expand Up @@ -555,12 +572,14 @@ void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::st


// Loop through the delta particles and incorporate into the base
bool hasIdentifier = (baseHasIdentifier0 && deltaHasIdentifier0) || (baseHasIdentifier1 && deltaHasIdentifier1);
for (int i=0; i<delta.numParticles(); ++i) {

// Grab index into base particle set - either existing or new
int index(-1);
if (hasIdentifier) {
int idValue = *(delta.data<int>(deltaIdAttr, i));
std::pair<int,int> idValue = std::make_pair(deltaHasIdentifier0 ? delta.data<int>(deltaIdAttr0, i)[0] : 0,
deltaHasIdentifier1 ? delta.data<int>(deltaIdAttr1, i)[0] : 0);
auto it = idToParticleIndex.find(idValue);
if (it != idToParticleIndex.end()) {
index = it->second;
Expand Down
2 changes: 1 addition & 1 deletion src/py/partio.i
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ ParticlesDataMutable* computeClustering(ParticlesDataMutable* particles,const in

%feature("autodoc");
%feature("docstring","Merge two particle sets");
void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier=std::string());
void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier0=std::string(), const std::string& identifier1=std::string());

/*
* We do NOT want swig to wrap partio's attrNameMap std::map<std::string, std::string>.
Expand Down
11 changes: 11 additions & 0 deletions src/tests/testmerge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ TEST_F(PartioTest, mergenoid)
{
}

TEST(MergeTest, mergepair)
{
std::string datadir(PARTIO_DATA_DIR);
std::string base_geo = datadir + "/baseidsfaceid.bgeo";
std::string delta_geo = datadir + "/deltaidsfaceid.bgeo";
Partio::ParticlesDataMutable* base = Partio::read(base_geo.c_str());
Partio::ParticlesDataMutable* delta = Partio::read(delta_geo.c_str());
Partio::merge(*base, *delta, "ids", "faceid_XS");
ASSERT_EQ(13, base->numParticles());
}

int main(int argc, char* argv[])
{
testing::InitGoogleTest(&argc, argv);
Expand Down

0 comments on commit b2b1305

Please sign in to comment.