fixed: wrap the multi-patch refinement in a loop
if not, neighbour patches will miss the refinements imposed by the extended refinement domain for a patch.
This commit is contained in:
parent
2d3aac464d
commit
6e5f087551
@ -27,7 +27,12 @@ install(FILES scripts/regtest.sh.in
|
||||
WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
# Unit tests
|
||||
IFEM_add_test_app(${PROJECT_SOURCE_DIR}/Test/*.C
|
||||
file(GLOB APPCOMMON_TEST_SRCS ${PROJECT_SOURCE_DIR}/Test/*.C)
|
||||
if(LRSpline_FOUND)
|
||||
list(APPEND APPCOMMON_TEST_SRCS ${PROJECT_SOURCE_DIR}/Test/LR/TestMultiPatchLRRefine.C)
|
||||
endif()
|
||||
|
||||
IFEM_add_test_app("${APPCOMMON_TEST_SRCS}"
|
||||
${PROJECT_SOURCE_DIR}/Test
|
||||
AppCommon
|
||||
IFEMAppCommon ${IFEM_LIBRARIES})
|
||||
|
131
Apps/Common/Test/LR/TestMultiPatchLRRefine.C
Normal file
131
Apps/Common/Test/LR/TestMultiPatchLRRefine.C
Normal file
@ -0,0 +1,131 @@
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file TestMultiPatchLRRefine.C
|
||||
//!
|
||||
//! \date Mar 31 2020
|
||||
//!
|
||||
//! \author Arne Morten Kvarving / SINTEF
|
||||
//!
|
||||
//! \brief Tests for multi-patch LR refinement.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "ASMbase.h"
|
||||
#include "ASMunstruct.h"
|
||||
#include "IntegrandBase.h"
|
||||
#include "MultiPatchModelGenerator.h"
|
||||
#include "SIMMultiPatchModelGen.h"
|
||||
#include "SIM2D.h"
|
||||
#include "SIM3D.h"
|
||||
#include "tinyxml.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
||||
// Dummy SIM class.
|
||||
template<class Dim>
|
||||
class RefineSim : public SIMMultiPatchModelGen<Dim>
|
||||
{
|
||||
public:
|
||||
RefineSim() : SIMMultiPatchModelGen<Dim>(Dim::dimension)
|
||||
{
|
||||
Dim::opt.discretization = ASM::LRSpline;
|
||||
}
|
||||
|
||||
bool parse(const TiXmlElement* elem) override
|
||||
{ return this->SIMMultiPatchModelGen<Dim>::parse(elem); }
|
||||
|
||||
virtual ~RefineSim() {}
|
||||
};
|
||||
|
||||
|
||||
class TestMultiPatchLRRefine2D :
|
||||
public testing::Test,
|
||||
public testing::WithParamInterface<int>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
TEST_P(TestMultiPatchLRRefine2D, Refine)
|
||||
{
|
||||
RefineSim<SIM2D> sim;
|
||||
TiXmlDocument doc;
|
||||
std::stringstream str;
|
||||
str << R"(<geometry dim="2" nx="2" ny="2">)"
|
||||
<< R"( <raiseorder lowerpatch="1" upperpatch="4)"
|
||||
<< R"(" u=")" << GetParam()
|
||||
<< R"(" v=")" << GetParam() << '"' << "/>"
|
||||
<< "</geometry>";
|
||||
doc.Parse(str.str().c_str());
|
||||
MultiPatchModelGenerator2D gen(doc.RootElement());
|
||||
EXPECT_TRUE(sim.parse(doc.RootElement()));
|
||||
EXPECT_TRUE(sim.preprocess());
|
||||
|
||||
srand(0);
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
LR::RefineData prm;
|
||||
sim.getPatch(1 + (rand() % 4))->getBoundaryNodes(1 + (rand() % 4), prm.elements);
|
||||
|
||||
prm.options.resize(3);
|
||||
prm.options[0] = 1;
|
||||
prm.options[1] = 1;
|
||||
prm.options[2] = 2;
|
||||
sim.refine(prm);
|
||||
sim.clearProperties();
|
||||
|
||||
ASSERT_TRUE(gen.createTopology(sim) && sim.preprocess());
|
||||
}
|
||||
}
|
||||
|
||||
class TestMultiPatchLRRefine3D :
|
||||
public testing::Test,
|
||||
public testing::WithParamInterface<int>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
TEST_P(TestMultiPatchLRRefine3D, Refine)
|
||||
{
|
||||
RefineSim<SIM3D> sim;
|
||||
TiXmlDocument doc;
|
||||
std::stringstream str;
|
||||
str << R"(<geometry dim="3" nx="2" ny="2" nz="2">)"
|
||||
<< R"( <raiseorder lowerpatch="1" upperpatch="8")"
|
||||
<< R"( u=")" << GetParam()
|
||||
<< R"(" v=")" << GetParam()
|
||||
<< R"(" w=")" << GetParam()
|
||||
<< '"' << "/>"
|
||||
<< "</geometry>";
|
||||
doc.Parse(str.str().c_str());
|
||||
MultiPatchModelGenerator3D gen(doc.RootElement());
|
||||
EXPECT_TRUE(sim.parse(doc.RootElement()));
|
||||
EXPECT_TRUE(sim.preprocess());
|
||||
|
||||
srand(0);
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
LR::RefineData prm;
|
||||
sim.getPatch(1 + (rand() % 8))->getBoundaryNodes(1 + (rand() % 6), prm.elements);
|
||||
|
||||
prm.options.resize(3);
|
||||
prm.options[0] = 1;
|
||||
prm.options[1] = 1;
|
||||
prm.options[2] = 2;
|
||||
sim.refine(prm);
|
||||
sim.clearProperties();
|
||||
|
||||
ASSERT_TRUE(gen.createTopology(sim) && sim.preprocess());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::vector<int> refValues = {0,1,2};
|
||||
INSTANTIATE_TEST_CASE_P(TestMultiPatchLRRefine2D,
|
||||
TestMultiPatchLRRefine2D,
|
||||
testing::ValuesIn(refValues));
|
||||
INSTANTIATE_TEST_CASE_P(TestMultiPatchLRRefine3D,
|
||||
TestMultiPatchLRRefine3D,
|
||||
testing::ValuesIn(refValues));
|
@ -1424,52 +1424,68 @@ bool SIMinput::refine (const LR::RefineData& prm, Vectors& sol)
|
||||
std::vector<LR::RefineData> prmloc(myModel.size(),LR::RefineData(prm));
|
||||
std::vector<IntSet> refineIndices(myModel.size());
|
||||
std::vector<IntSet> conformingIndices(myModel.size());
|
||||
for (size_t i = 0; i < myModel.size(); i++)
|
||||
{
|
||||
// Extract local indices from the vector of global indices
|
||||
int locId;
|
||||
for (int k : prm.elements)
|
||||
if ((locId = myModel[i]->getNodeIndex(k+1)) > 0)
|
||||
refineIndices[i].insert(locId-1);
|
||||
|
||||
// fetch all boundary nodes covered (may need to pass this to other patches)
|
||||
pch = dynamic_cast<ASMunstruct*>(myModel[i]);
|
||||
IntVec bndry_nodes = pch->getBoundaryCovered(refineIndices[i]);
|
||||
|
||||
// DESIGN NOTE: It is tempting here to use patch connectivity information.
|
||||
// However, this does not account (in the general case)
|
||||
// for cross-connections in L-shape geometries, i.e.,
|
||||
//
|
||||
// +-----+
|
||||
// | #1 |
|
||||
// | | patch #1 (edge 3) connected to patch #2 (edge 4)
|
||||
// +-----+-----+ patch #2 (edge 2) connected to patch #3 (edge 1)
|
||||
// | #2 | #3 |
|
||||
// | | | we need to pass the corner index of patch #3 (vertex 3)
|
||||
// +-----+-----+ to patch #1 (vertex 2), but this connection is not
|
||||
// guaranteed to appear in the input file
|
||||
|
||||
// for all boundary nodes, check if these appear on other patches
|
||||
for (int k : bndry_nodes)
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (size_t i = 0; i < myModel.size(); i++)
|
||||
{
|
||||
int globId = myModel[i]->getNodeID(k+1);
|
||||
for (size_t j = 0; j < myModel.size(); j++)
|
||||
if (j != i && (locId = myModel[j]->getNodeIndex(globId)) > 0)
|
||||
{
|
||||
conformingIndices[j].insert(locId-1);
|
||||
conformingIndices[i].insert(k);
|
||||
// Extract local indices from the vector of global indices
|
||||
int locId;
|
||||
for (int k : prm.elements)
|
||||
if ((locId = myModel[i]->getNodeIndex(k+1)) > 0) {
|
||||
if (refineIndices[i].count(locId-1) == 0) {
|
||||
refineIndices[i].insert(locId-1);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// fetch all boundary nodes covered (may need to pass this to other patches)
|
||||
pch = dynamic_cast<ASMunstruct*>(myModel[i]);
|
||||
IntVec bndry_nodes = pch->getBoundaryCovered(refineIndices[i]);
|
||||
|
||||
// DESIGN NOTE: It is tempting here to use patch connectivity information.
|
||||
// However, this does not account (in the general case)
|
||||
// for cross-connections in L-shape geometries, i.e.,
|
||||
//
|
||||
// +-----+
|
||||
// | #1 |
|
||||
// | | patch #1 (edge 3) connected to patch #2 (edge 4)
|
||||
// +-----+-----+ patch #2 (edge 2) connected to patch #3 (edge 1)
|
||||
// | #2 | #3 |
|
||||
// | | | we need to pass the corner index of patch #3 (vertex 3)
|
||||
// +-----+-----+ to patch #1 (vertex 2), but this connection is not
|
||||
// guaranteed to appear in the input file
|
||||
|
||||
// for all boundary nodes, check if these appear on other patches
|
||||
for (int k : bndry_nodes)
|
||||
{
|
||||
int globId = myModel[i]->getNodeID(k+1);
|
||||
for (size_t j = 0; j < myModel.size(); j++)
|
||||
if (j != i && (locId = myModel[j]->getNodeIndex(globId)) > 0)
|
||||
{
|
||||
if (conformingIndices[j].count(locId-1) == 0) {
|
||||
changed = true;
|
||||
conformingIndices[j].insert(locId-1);
|
||||
conformingIndices[i].insert(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < myModel.size(); i++)
|
||||
{
|
||||
pch = dynamic_cast<ASMunstruct*>(myModel[i]);
|
||||
pch->extendRefinementDomain(refineIndices[i],conformingIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Vectors lsols;
|
||||
lsols.reserve(sol.size()*myModel.size());
|
||||
size_t ngNodes = this->getNoNodes(1);
|
||||
|
||||
for (size_t i = 0; i < myModel.size(); i++)
|
||||
{
|
||||
pch = dynamic_cast<ASMunstruct*>(myModel[i]);
|
||||
pch->extendRefinementDomain(refineIndices[i],conformingIndices[i]);
|
||||
|
||||
LR::RefineData prmloc(prm);
|
||||
prmloc.elements = IntVec(refineIndices[i].begin(),refineIndices[i].end());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user