Skip to content

Conversation

Angelyr
Copy link
Collaborator

@Angelyr Angelyr commented Aug 6, 2025

Changes to coarsen

  • improvement to independent set
  • fixed bug that made it impossible to collapse edge in both directions
  • fixed bug that made it slower to collapse in one direction in parallel
  • added multi-step coarsen

Changes to snapping

  • fixed bug with snapping coarsening the mesh too mush
  • fixed bug where not all regions were included in first problem plane
  • should snap vertices in most cases
  • added quality settings for split collapse

More testing

  • added test for common errors in coarsen, refinement and snapping

Most of the these changes to snapping and coarsen came from Li's thesis with some minor exceptions:

  • In the coarsen procedure in Li's thesis it describes getting the shortest edge next to a vertex and collapsing it. We found we had better results if we try collapsing the shortest edge and then grab the next shortest until one succeeds.
  • Another difference is that Li's thesis mentions collapses, but it has very little detail in how those collapses are selected, so our logic for collapses is taken from our old mesh adapt library.
  • Li's thesis also describes using FaceSwap in snapping and vertex repositioning in snapping and coarsen, but we haven't created either of those operators yet.

@cwsmith
Copy link
Contributor

cwsmith commented Aug 9, 2025

/runtests

@cwsmith
Copy link
Contributor

cwsmith commented Aug 9, 2025

@Angelyr Thank you. I pushed the sim version change to develop and once it appears in master tomorrow morning runtests will use it.

@cwsmith
Copy link
Contributor

cwsmith commented Aug 11, 2025

/runtests

@cwsmith
Copy link
Contributor

cwsmith commented Aug 11, 2025

@Angelyr Would you please take a look at the failing test:

 8/95 Test  #8: bezierRefine .....................***Failed    0.23 sec

in the (gcc-10, g++-10, Debug, OFF, 20, ON) config?

@Angelyr
Copy link
Collaborator Author

Angelyr commented Aug 11, 2025

@cwsmith Yes I will take a look.

Copy link

Build Log
Simmetrix Test Result: success
Simmetrix + CGNS Test Result: success

@Angelyr
Copy link
Collaborator Author

Angelyr commented Aug 13, 2025

@cwsmith I was struggling to recreate the issue locally, but I re-ran the test and it passed

@cwsmith
Copy link
Contributor

cwsmith commented Aug 13, 2025

OK. Thanks for the heads up. A couple things we could try come to mind:

  • run the test a bunch of times with ctest --repeat-until-fail 100
  • check for memory errors in the test with valgrind

@Angelyr
Copy link
Collaborator Author

Angelyr commented Aug 13, 2025

@cwsmith I fixed an uninitialized value in 2d cases. That might have been the issue

@cwsmith
Copy link
Contributor

cwsmith commented Aug 13, 2025

@Angelyr Looks good. All the github hosted ci tests are passing. Thank you.

(Note: I still need to read through the changes)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the changes fall into following categories (or more) so add comments like this throughout the code that's changed:

  • key logic changes to adapt as per Li's thesis
  • key logic changes to adapt as discussed in meeting - a sentence that summarizes discussion
  • bug fixes in operators
  • memory issues or low level software fixes
    and so on..

Copy link
Collaborator Author

@Angelyr Angelyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added comments to aid with reviewing the PR

Comment on lines +78 to +80
/* we are starting to support a few operations on matched
meshes, sincluding snapping+UR. this should prevent snapping
from modifying any matched entities */
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved comment from snapping to relevant function

MatchedSnapper::MatchedSnapper(Adapt* a, Tag* st, bool is)
MatchedSnapper::MatchedSnapper(Adapt* a, Tag* st)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The option for simple snapping has been removed. This option would stop the snapping procedure from collapsing resulting in vertices that didn't snap.

ma/maSnap.cc Outdated
Comment on lines 33 to 43
static bool isCapstoneMesh(apf::Mesh* m)
{
#ifdef HAVE_CAPSTONE
if (dynamic_cast<apf::MeshCAP*>(m)) return true;
else return false;
#else
(void)m;
return false;
#endif
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most the changes in this file involve the replacement of a compile time capstone flag with a runtime capstone flag to ensure that these changes are being used on non-capstone meshes

Comment on lines +140 to +141
if (period < 0.5) //partial range can't be periodic
return (1-t)*a + t*b;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved bug caused by meshes in capstone can have partial ranges that aren't periodic

ma/maSnap.cc Outdated
Comment on lines 868 to 971
bool snapped = true;
int prevTagged = 0;
while (snapped) {
int tagged = tagVertsToSnap(a, tag);
if (tagged == prevTagged) break;
prevTagged = tagged;
if (a->mesh->hasMatching())
snapped = snapMatchedVerts(a, tag, successCount);
else
snapped = snapAllVerts(a, tag, snapper);
}

a->input->shouldForceAdaptation = shouldForce;
return successCount;
}

int collect(Adapt* a, int val) {
return a->mesh->getPCU()->Add<long>(val);
}

void snap(Adapt* a)
{
if ( ! a->input->shouldSnap)
if (!a->input->shouldSnap)
return;
double t0 = pcu::Time();
Tag* tag;
/* we are starting to support a few operations on matched
meshes, including snapping+UR. this should prevent snapping
from modifying any matched entities */
Tag* snapTag = a->mesh->createDoubleTag("ma_snap", 3);
preventMatchedCavityMods(a);
long targets = tagVertsToSnap(a, tag);
long success = snapTaggedVerts(a, tag);
snapLayer(a, tag);
apf::removeTagFromDimension(a->mesh, tag, 0);
a->mesh->destroyTag(tag);
double t1 = pcu::Time();
print(a->mesh->getPCU(), "snapped in %f seconds: %ld targets, %ld non-layer snaps",
t1 - t0, targets, success);
if (a->hasLayer)
checkLayerShape(a->mesh, "after snapping");
}

void visualizeGeometricInfo(Mesh* m, const char* name)
{
Tag* dimensionTag = m->createIntTag("ma_geom_dim",1);
Tag* idTag = m->createIntTag("ma_geom_id",1);
apf::Field* field = apf::createLagrangeField(m,"ma_param",apf::VECTOR,1);
apf::Field* targetField = apf::createLagrangeField(m,"ma_target",apf::VECTOR,1);
Iterator* it = m->begin(0);
Entity* v;
while ((v = m->iterate(it)))
{
Model* c = m->toModel(v);
int dimension = m->getModelType(c);
m->setIntTag(v,dimensionTag,&dimension);
int id = m->getModelTag(c);
m->setIntTag(v,idTag,&id);
Vector p;
Vector xp = getPosition(m, v);
m->getParam(v,p);
if (dimension == 2 || dimension == 1) {
Vector x;
m->isParamPointInsideModel(c, &p[0], x);
apf::setVector(targetField, v, 0, x - xp);
}
else {
Vector x(0., 0., 0.);
apf::setVector(targetField, v, 0, x);
}
apf::setVector(field,v,0,p);
}
m->end(it);
apf::writeVtkFiles(name,m);
it = m->begin(0);
while ((v = m->iterate(it)))
int toSnap = tagVertsToSnap(a, snapTag);
if (toSnap)
{
m->removeTag(v,dimensionTag);
m->removeTag(v,idTag);
Snapper snapper(a, snapTag);
snapTaggedVerts(a, snapTag, snapper);
snapLayer(a, snapTag);

double t1 = pcu::Time();
print(a->mesh->getPCU(), "ToSnap %d - Moved %d - Failed %d - CollapseToVtx %d - Collapse %d - Swap %d - SplitCollapse %d - completed in %f seconds",
toSnap, collect(a,snapper.numSnapped), collect(a,snapper.numFailed), collect(a,snapper.numCollapseToVtx), collect(a,snapper.numCollapse), collect(a,snapper.numSwap), collect(a,snapper.numSplitCollapse), t1 - t0);
if (a->hasLayer)
checkLayerShape(a->mesh, "after snapping");
}
m->end(it);
m->destroyTag(dimensionTag);
m->destroyTag(idTag);
apf::destroyField(field);
apf::destroyField(targetField);
a->mesh->destroyTag(snapTag);
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified old snapping logic since it was overly complicated

Comment on lines -357 to +742
dists.push_back(minDist + 1.0 + tol);
dists.push_back(newDirection.getLength());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed bug that prevented some coplanar regions from being included in first problem plane

adaptMesh, apf::GRAPH, apf::PARTITION
mesh, apf::GRAPH, apf::PARTITION
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed typo

Comment on lines -77 to +116
if (tryThisDirection(qualityToBeat))
if (tryThisDirectionNoCancel(qualityToBeat))
return true;
if ( ! getFlag(adapt,vertToKeep,COLLAPSE))
return false;
std::swap(vertToKeep,vertToCollapse);
computeElementSets();
if (!adapt->input->shouldForceAdaptation)
qualityToBeat = std::min(adapt->input->goodQuality,
std::max(getOldQuality(),adapt->input->validQuality));
else destroyNewElements();

if (getFlag(adapt,vertToKeep,COLLAPSE)) {
std::swap(vertToKeep,vertToCollapse);
computeElementSets();
if (tryThisDirectionNoCancel(qualityToBeat))
return true;
else destroyNewElements();
}

return tryThisDirection(qualityToBeat);
unmark();
return false;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a bug in this function that prevented collapsing an edge in either direction. These changes result in both vertices being considered for collapse.

Comment on lines -130 to +162
PCU_ALWAYS_ASSERT( ! m->isShared(v[0]));
PCU_ALWAYS_ASSERT( ! m->isShared(v[1]));
if (!getFlag(a, v[0], DONT_COLLAPSE)) //Allow collapse in one direction
PCU_ALWAYS_ASSERT( ! m->isShared(v[0]));
if (!getFlag(a, v[1], DONT_COLLAPSE)) //Allow collapse in one direction
PCU_ALWAYS_ASSERT( ! m->isShared(v[1]));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug that prevented collapsing and edge in one direction in parallel when only the collapsing vertex was owned by the current process

@cwsmith
Copy link
Contributor

cwsmith commented Aug 26, 2025

@Angelyr Would you please move your comments above into the code if they are not already there?

@joshia5 Are you done with your review?

@cwsmith cwsmith added the v4.1.0 changes included in the 4.1.0 release label Aug 26, 2025
@joshia5
Copy link
Contributor

joshia5 commented Aug 26, 2025

@cwsmith I'll take a look

@cwsmith cwsmith mentioned this pull request Aug 26, 2025
@Angelyr Angelyr linked an issue Aug 27, 2025 that may be closed by this pull request
ma/maSize.h Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L22,23 since we defined these as input parameters, I'm inclined to have them in maInput unless I can think a good reason why not, tbd

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark mentioned that we should not be modifying this value at this point, I added a comment about it.

@@ -253,4 +257,211 @@ bool coarsen(Adapt* a)
return true;
}

//Measure and edge lenght and stores the result so it doesn't have to be calculated again
Copy link
Contributor

@joshia5 joshia5 Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should have been computing edge lengths downstream in markEdgesToCollapse/Split , I was suggesting to add/store the tag where that is done. or are those markedges modified and now calling this new getLength?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The confusion is that there are two separate implementations of coarsen in this file and only one of them uses this getLength function. It would not be useful in the old implementation of coarsen since that implementation only calculates the length once anyway.

@Angelyr
Copy link
Collaborator Author

Angelyr commented Aug 30, 2025

@bobpaw Feel free to take a look at the code now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v4.1.0 changes included in the 4.1.0 release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ac/adapt-changes dpw6
4 participants