Skip to content

Commit 83dfbb2

Browse files
Nightly BotSichao25
authored andcommitted
Merging develop into master
2 parents 6a972af + 40ecac1 commit 83dfbb2

36 files changed

+1477
-453
lines changed

cdash/nightly.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ unset MODULEPATH
1111
module use /opt/scorec/spack/rhel9/v0201_4/lmod/linux-rhel9-x86_64/Core/
1212
module load gcc/12.3.0-iil3lno
1313
module load mpich/4.1.1-xpoyz4t
14-
module load simmetrix-simmodsuite/2024.0-240119dev-7abimo4
14+
module load simmetrix-simmodsuite/2025.0-250108dev-llxq6sk
1515
module load zoltan/3.83-hap4ggo
1616
module load cmake/3.26.3-2duxfcd
1717
module load cgns/develop-cc4dfwp

cmake/FindSimModSuite.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ string(REGEX REPLACE
8484
"${SIM_VERSION}")
8585

8686
set(MIN_VALID_SIM_VERSION 15.0.191017)
87-
set(MAX_VALID_SIM_VERSION 2025.0.241016)
87+
set(MAX_VALID_SIM_VERSION 2025.0.250108)
8888
if( ${SKIP_SIMMETRIX_VERSION_CHECK} )
8989
message(STATUS "Skipping Simmetrix SimModSuite version check."
9090
" This may result in undefined behavior")

gmi_cap/gmi_cap.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,7 @@ GDBI* gmi_export_cap(gmi_model* m)
541541
cap_model* cm = (cap_model*)m;
542542
return cm->geomInterface;
543543
}
544+
545+
int gmi_cap_test(struct gmi_model* model) {
546+
return model->ops == &ops ? 1 : 0;
547+
}

gmi_cap/gmi_cap.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct gmi_ent;
5757
* \note This call is required before calling any other gmi_cap functions.
5858
*/
5959
void gmi_cap_start(void);
60+
6061
/**
6162
* \brief Finalize gmi_cap library.
6263
*
@@ -94,6 +95,15 @@ struct gmi_model* gmi_cap_load(const char* creFileName);
9495
*/
9596
void gmi_cap_write(struct gmi_model* model, const char* creFileName);
9697

98+
/**
99+
* \brief Test if model is a Capstone gmi_model.
100+
*
101+
* \param model An abstract gmi_model which may have an underlying Capstone
102+
* database.
103+
* \return 1 if model is a Capstone gmi_model and 0 otherwise.
104+
*/
105+
int gmi_cap_test(struct gmi_model* model);
106+
97107
#ifdef __cplusplus
98108

99109
/**

ma/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ target_link_libraries(ma
8585
pcu
8686
)
8787

88+
if (ENABLE_CAPSTONE)
89+
target_link_libraries(ma PRIVATE apf_cap)
90+
endif()
91+
8892
scorec_export_library(ma)
8993

9094
bob_end_subdir()

ma/ma.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void adaptVerbose(Input* in, bool verbose)
100100
int count = 0;
101101
double lMax = ma::getMaximumEdgeLength(a->mesh, a->sizeField);
102102
print(a->mesh->getPCU(), "Maximum (metric) edge length in the mesh is %f", lMax);
103-
while (lMax > 1.5) {
103+
while (lMax > MAXLENGTH) {
104104
print(a->mesh->getPCU(), "%dth additional refine-snap call", count);
105105
refine(a);
106106
snap(a);

ma/maCoarsen.cc

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,81 @@
77
of the SCOREC Non-Commercial License this program is distributed under.
88
99
*******************************************************************************/
10+
/*
11+
This file contains two coarsening alogrithms.
12+
1. coarsenMultiple: will repeatedly create independent sets and collapse the mesh
13+
until there are no more short edges left. This code is currently only used for testing
14+
since more work needs to be done to achieve better performance and have the code work in
15+
parallel, at which point the other coarsen algorithm can be deleted.
16+
2. coarsen: The first will create one independent set and then collapse all of the edges
17+
in that independent set.
18+
*/
1019
#include "maCoarsen.h"
1120
#include "maAdapt.h"
1221
#include "maCollapse.h"
1322
#include "maMatchedCollapse.h"
1423
#include "maOperator.h"
24+
#include "maDBG.h"
1525
#include <pcu_util.h>
26+
#include "apfShape.h"
27+
#include <vector>
28+
#include <list>
29+
#include <algorithm>
1630

1731
namespace ma {
1832

33+
namespace {
34+
35+
//Measures edge length and stores the result so it doesn't have to be calculated again
36+
double getLength(Adapt* a, Tag* lengthTag, Entity* edge)
37+
{
38+
double length = 0;
39+
if (a->mesh->hasTag(edge, lengthTag))
40+
a->mesh->getDoubleTag(edge, lengthTag, &length);
41+
else {
42+
length = a->sizeField->measure(edge);
43+
a->mesh->setDoubleTag(edge, lengthTag, &length);
44+
}
45+
return length;
46+
}
47+
48+
//Make sure that a collapse will not create an edge longer than the max
49+
bool collapseSizeCheck(Adapt* a, Entity* vertex, Entity* edge, apf::Up& adjacent)
50+
{
51+
Entity* vCollapse = getEdgeVertOppositeVert(a->mesh, edge, vertex);
52+
for (int i=0; i<adjacent.n; i++) {
53+
Entity* newEdgeVerts[2]{vertex, getEdgeVertOppositeVert(a->mesh, adjacent.e[i], vCollapse)};
54+
Entity* newEdge = a->mesh->createEntity(apf::Mesh::EDGE, 0, newEdgeVerts);
55+
double length = a->sizeField->measure(newEdge);
56+
destroyElement(a, newEdge);
57+
if (length > MAXLENGTH) return false;
58+
}
59+
return true;
60+
}
61+
62+
bool tryCollapseEdge(Adapt* a, Entity* edge, Entity* keep, Collapse& collapse, apf::Up& adjacent)
63+
{
64+
PCU_ALWAYS_ASSERT(a->mesh->getType(edge) == apf::Mesh::EDGE);
65+
bool alreadyFlagged = true;
66+
if (keep) alreadyFlagged = getFlag(a, keep, DONT_COLLAPSE);
67+
if (!alreadyFlagged) setFlag(a, keep, DONT_COLLAPSE);
68+
69+
double quality = a->input->shouldForceAdaptation ? a->input->validQuality
70+
: a->input->goodQuality;
71+
72+
bool result = false;
73+
if (collapse.setEdge(edge) &&
74+
collapse.checkClass() &&
75+
collapse.checkTopo() &&
76+
collapseSizeCheck(a, keep, edge, adjacent) &&
77+
collapse.tryBothDirections(quality)) {
78+
result = true;
79+
}
80+
if (!alreadyFlagged) clearFlag(a, keep, DONT_COLLAPSE);
81+
return result;
82+
}
83+
}
84+
1985
class CollapseChecker : public apf::CavityOp
2086
{
2187
public:
@@ -253,4 +319,153 @@ bool coarsen(Adapt* a)
253319
return true;
254320
}
255321

322+
/*
323+
To be used after collapsing a vertex to flag adjacent vertices as NEED_NOT_COLLAPSE. This will create a
324+
set of collapses where no two adjacent are vertices collapsed. Will also clear adjacent vertices for
325+
collapse in next independent set since they might succeed after a collapse.
326+
*/
327+
void flagIndependentSet(Adapt* a, apf::Up& adjacent, size_t& checked)
328+
{
329+
for (int adj=0; adj < adjacent.n; adj++) {
330+
Entity* vertices[2];
331+
a->mesh->getDownward(adjacent.e[adj],0, vertices);
332+
for (int v = 0; v < 2; v++) {
333+
setFlag(a, vertices[v], NEED_NOT_COLLAPSE);
334+
if (getFlag(a, vertices[v], CHECKED)){
335+
clearFlag(a, vertices[v], CHECKED); //needs to be checked again in next independent set
336+
checked--;
337+
}
338+
}
339+
}
340+
}
341+
342+
struct EdgeLength
343+
{
344+
Entity* edge;
345+
double length;
346+
bool operator<(const EdgeLength& other) const {
347+
return length < other.length;
348+
}
349+
};
350+
351+
/*
352+
Given an iterator pointing to a vertex we will collapse the shortest adjacent edge and try the next
353+
shorted until one succeeds and then it will expand independent set. In Li's thesis it only attempts
354+
to collapse the shortest edge, but this gave us better results.
355+
*/
356+
bool collapseShortest(Adapt* a, Collapse& collapse, std::list<Entity*>& shortEdgeVerts, std::list<Entity*>::iterator& itr, size_t& checked, apf::Up& adjacent, Tag* lengthTag)
357+
{
358+
Entity* vertex = *itr;
359+
std::vector<EdgeLength> sorted;
360+
for (int i=0; i < adjacent.n; i++) {
361+
double length = getLength(a, lengthTag, adjacent.e[i]);
362+
EdgeLength measured{adjacent.e[i], length};
363+
if (measured.length > MINLENGTH) continue;
364+
sorted.push_back(measured);
365+
}
366+
if (sorted.size() == 0) { //performance optimization, will rarely result in a missed edge
367+
itr = shortEdgeVerts.erase(itr);
368+
return false;
369+
}
370+
std::sort(sorted.begin(), sorted.end());
371+
for (size_t i=0; i < sorted.size(); i++) {
372+
Entity* keepVertex = getEdgeVertOppositeVert(a->mesh, sorted[i].edge, vertex);
373+
if (!tryCollapseEdge(a, sorted[i].edge, keepVertex, collapse, adjacent)) continue;
374+
flagIndependentSet(a, adjacent, checked);
375+
itr = shortEdgeVerts.erase(itr);
376+
collapse.destroyOldElements();
377+
return true;
378+
}
379+
setFlag(a, vertex, CHECKED);
380+
checked++;
381+
return false;
382+
}
383+
384+
/*
385+
Iterates through shortEdgeVerts until it finds a vertex that is adjacent to an
386+
independent set. We want our collapses to touch the independent set in order to
387+
reduce adjacent collapses, since collapsing adjacent vertices will result in a
388+
lower quality mesh.
389+
*/
390+
bool getAdjIndependentSet(Adapt* a, std::list<Entity*>& shortEdgeVerts, std::list<Entity*>::iterator& itr, bool& independentSetStarted, apf::Up& adjacent)
391+
{
392+
size_t numItr=0;
393+
do {
394+
numItr++;
395+
if (itr == shortEdgeVerts.end()) itr = shortEdgeVerts.begin();
396+
Entity* vertex = *itr;
397+
if (getFlag(a, vertex, CHECKED)) {itr++; continue;} //Already tried to collapse
398+
a->mesh->getUp(vertex, adjacent);
399+
if (!independentSetStarted) return true;
400+
if (getFlag(a, vertex, NEED_NOT_COLLAPSE)) {itr++; continue;} //Too close to last collapse
401+
for (int i=0; i < adjacent.n; i++)
402+
{
403+
Entity* opposite = getEdgeVertOppositeVert(a->mesh, adjacent.e[i], vertex);
404+
if (getFlag(a, opposite, NEED_NOT_COLLAPSE)) return true; //Touching independent set
405+
}
406+
itr++;
407+
} while (numItr < shortEdgeVerts.size());
408+
for (auto v : shortEdgeVerts) clearFlag(a, v, NEED_NOT_COLLAPSE);
409+
independentSetStarted = false;
410+
return false;
411+
}
412+
413+
//returns a list of vertices that bound a short edge and flags them
414+
std::list<Entity*> getShortEdgeVerts(Adapt* a, Tag* lengthTag)
415+
{
416+
std::list<Entity*> shortEdgeVerts;
417+
Iterator* it = a->mesh->begin(1);
418+
Entity* edge;
419+
while ((edge = a->mesh->iterate(it)))
420+
{
421+
double length = getLength(a, lengthTag, edge);
422+
if (length > MINLENGTH) continue;
423+
Entity* vertices[2];
424+
a->mesh->getDownward(edge,0,vertices);
425+
for (int i = 0; i < 2; i++) {
426+
if (getFlag(a, vertices[i], CHECKED)) continue;
427+
setFlag(a, vertices[i], CHECKED);
428+
shortEdgeVerts.push_back(vertices[i]);
429+
}
430+
}
431+
for (auto v : shortEdgeVerts) clearFlag(a, v, CHECKED);
432+
a->mesh->end(it);
433+
return shortEdgeVerts;
434+
}
435+
436+
/*
437+
Follows the alogritm in Li's thesis in order to coarsen all short edges
438+
in a mesh while maintaining a decent quality mesh.
439+
*/
440+
bool coarsenMultiple(Adapt* a)
441+
{
442+
if (!a->input->shouldCoarsen)
443+
return false;
444+
double t0 = pcu::Time();
445+
Tag* lengthTag = a->mesh->createDoubleTag("edge_length", 1);
446+
std::list<Entity*> shortEdgeVerts = getShortEdgeVerts(a, lengthTag);
447+
448+
Collapse collapse;
449+
collapse.Init(a);
450+
int success = 0;
451+
size_t checked = 0;
452+
bool independentSetStarted = false;
453+
std::list<Entity*>::iterator itr = shortEdgeVerts.begin();
454+
while (checked < shortEdgeVerts.size())
455+
{
456+
apf::Up adjacent;
457+
if (!getAdjIndependentSet(a, shortEdgeVerts, itr, independentSetStarted, adjacent)) continue;
458+
if (collapseShortest(a, collapse, shortEdgeVerts, itr, checked, adjacent, lengthTag)) {
459+
independentSetStarted=true;
460+
success++;
461+
}
462+
}
463+
ma::clearFlagFromDimension(a, NEED_NOT_COLLAPSE | CHECKED, 0);
464+
a->mesh->destroyTag(lengthTag);
465+
double t1 = pcu::Time();
466+
print(a->mesh->getPCU(), "coarsened %d edges in %f seconds", success, t1-t0);
467+
return true;
468+
}
469+
470+
256471
}

ma/maCoarsen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace ma {
1414

1515
class Adapt;
1616

17+
bool coarsenMultiple(Adapt* a);
1718
bool coarsen(Adapt* a);
1819
bool coarsenLayer(Adapt* a);
1920

ma/maCollapse.cc

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,34 @@ bool Collapse::tryThisDirectionNoCancel(double qualityToBeat)
5555
return true;
5656
}
5757

58+
/*Sometimes the snapping procedure will attempt to collapse a edge that was just
59+
refined. This function will prevent that when the growth of the edge is above a
60+
thresh hold where it might not reach the target edge length*/
61+
bool Collapse::edgesGoodSize() {
62+
PCU_ALWAYS_ASSERT(elementsToKeep.size());
63+
PCU_ALWAYS_ASSERT(elementsToKeep.size() == newElements.size());
64+
size_t i=0;
65+
double maxSize=0;
66+
double ratioAtMaxSize=0;
67+
APF_ITERATE(EntitySet,elementsToKeep,it) {
68+
Entity* edgesBefore[6];
69+
adapt->mesh->getDownward(*it,1,edgesBefore);
70+
Entity* edgesAfter[6];
71+
adapt->mesh->getDownward(newElements[i++],1,edgesAfter);
72+
for (int j=0; j<6; j++) {
73+
double sizeBefore = adapt->sizeField->measure(edgesBefore[j]);
74+
double sizeAfter = adapt->sizeField->measure(edgesAfter[j]);
75+
double ratio = sizeAfter/sizeBefore;
76+
if (sizeAfter > maxSize) {
77+
maxSize = sizeAfter;
78+
ratioAtMaxSize = ratio;
79+
}
80+
}
81+
}
82+
if (maxSize > MAXLENGTH && ratioAtMaxSize > MAXLENGTHRATIO) return false;
83+
return true;
84+
}
85+
5886
bool Collapse::tryThisDirection(double qualityToBeat)
5987
{
6088
if (!tryThisDirectionNoCancel(qualityToBeat)) {
@@ -74,17 +102,20 @@ bool Collapse::tryBothDirections(double qualityToBeat)
74102
qualityToBeat = std::min(adapt->input->goodQuality,
75103
std::max(getOldQuality(),adapt->input->validQuality));
76104

77-
if (tryThisDirection(qualityToBeat))
105+
if (tryThisDirectionNoCancel(qualityToBeat))
78106
return true;
79-
if ( ! getFlag(adapt,vertToKeep,COLLAPSE))
80-
return false;
81-
std::swap(vertToKeep,vertToCollapse);
82-
computeElementSets();
83-
if (!adapt->input->shouldForceAdaptation)
84-
qualityToBeat = std::min(adapt->input->goodQuality,
85-
std::max(getOldQuality(),adapt->input->validQuality));
107+
else destroyNewElements();
108+
109+
if (getFlag(adapt,vertToKeep,COLLAPSE)) {
110+
std::swap(vertToKeep,vertToCollapse);
111+
computeElementSets();
112+
if (tryThisDirectionNoCancel(qualityToBeat))
113+
return true;
114+
else destroyNewElements();
115+
}
86116

87-
return tryThisDirection(qualityToBeat);
117+
unmark();
118+
return false;
88119
}
89120

90121
bool Collapse::setEdge(Entity* e)
@@ -127,8 +158,10 @@ bool checkEdgeCollapseEdgeRings(Adapt* a, Entity* edge)
127158
Mesh* m = a->mesh;
128159
Entity* v[2];
129160
m->getDownward(edge,0,v);
130-
PCU_ALWAYS_ASSERT( ! m->isShared(v[0]));
131-
PCU_ALWAYS_ASSERT( ! m->isShared(v[1]));
161+
if (!getFlag(a, v[0], DONT_COLLAPSE)) //Allow collapse in one direction
162+
PCU_ALWAYS_ASSERT( ! m->isShared(v[0]));
163+
if (!getFlag(a, v[1], DONT_COLLAPSE)) //Allow collapse in one direction
164+
PCU_ALWAYS_ASSERT( ! m->isShared(v[1]));
132165
apf::Up ve[2];
133166
m->getUp(v[0],ve[0]);
134167
m->getUp(v[1],ve[1]);

ma/maCollapse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class Collapse
4141
bool tryThisDirectionNoCancel(double qualityToBeat);
4242
bool tryBothDirections(double qualityToBeat);
4343
void getOldElements(EntityArray& oldElements);
44+
bool edgesGoodSize();
4445
double getOldQuality();
4546
Adapt* adapt;
4647
Entity* edge;

0 commit comments

Comments
 (0)