optimad/bitpit

surfunstructured ~ incorrect cell getInterfaceCount(edge) result

Closed this issue · 7 comments

Task: Create a two interfaces on edge 0.

Problem:

  • The interfaces are correctly stored in the surfunstructured but calling getInterfaceCount(edge) from the owner face returns the wrong result.

Printed result from displayInterfaces():
interface:
interface type: 3
ID: 0
is border: (true)
connectivity: [ 0, 4 ]
onwer ID: 0
owner face: 0

interface:
interface type: 3
ID: 4
is border: (true)
connectivity: [ 4, 1 ]
onwer ID: 0
owner face: 0

Reproducer:
`
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

auto surface = std::make_unique<exam::SurfUnstructured>(3, 3, MPI_COMM_WORLD);
const auto v0It = surface->addVertex({0, 0, 0}, 0);
const auto v1It = surface->addVertex({5, 0, 0}, 1);
const auto v2It = surface->addVertex({5, 10, 0}, 2);
const auto v3It = surface->addVertex({0, 10, 0}, 3);
const auto vXIt = surface->addVertex({2.5, 0, 0}, 4);

const long faceId = 0;
std::vector<long> surfaceCellConnect = {v0It->getId(), v1It->getId(), v2It->getId(), v3It->getId()};
surface->addCell(bitpit::ElementType::QUAD, surfaceCellConnect, rank, faceId);

surface->initializeAdjacencies();
surface->initializeInterfaces();
surface->update();

EXPECT_EQ(surface->getCell(faceId).getInterfaceCount(0), 2);
EXPECT_EQ(surface->getCell(faceId).getInterfaceCount(1), 1);
EXPECT_EQ(surface->getCell(faceId).getInterfaceCount(2), 1);
EXPECT_EQ(surface->getCell(faceId).getInterfaceCount(3), 1);

// V0 to V1 Interface
surface->deleteInterface(surface->getCell(faceId).getInterface(0, 0));
surface->addInterface(bitpit::ElementType::LINE, {v0It->getId(), vXIt->getId()})->setOwner(faceId, 0);
surface->addInterface(bitpit::ElementType::LINE, {vXIt->getId(), v1It->getId()})->setOwner(faceId, 0);

surface->update(true);
surface->displayInterfaces(std::cout);

EXPECT_EQ(surface->getCell(faceId).getInterfaceCount(0), 2); // This returns 1 when it should be 2.

`

Thanks for the test case. I will work on it.

Thanks @andrea-iob, please let me know your findings when you have any as I'm working on fixing a bug and think it's coming from this.

Thanks,
Denis

`
TEST(SplitInterface, SplitEdge0) {
// How to insert new interface.
// Task: Split v0 to v1 edge with v0 to vX and vX to v1.

int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

auto surface = std::make_unique<exam::SurfUnstructured>(3, 3, MPI_COMM_WORLD);
const auto v0It = surface->addVertex({0, 0, 0}, 0);
const auto v1It = surface->addVertex({5, 0, 0}, 1);
const auto v2It = surface->addVertex({5, 10, 0}, 2);
const auto v3It = surface->addVertex({0, 10, 0}, 3);
const auto vXIt = surface->addVertex({2.5, 0, 0}, 4);

const long faceId = 0;
std::vector<long> surfaceCellConnect = {v0It->getId(), v1It->getId(), v2It->getId(), v3It->getId()};
surface->addCell(bitpit::ElementType::QUAD, surfaceCellConnect, rank, faceId);
surface->initializeAdjacencies();
surface->initializeInterfaces();
surface->update();

auto& cell = surface->getCell(faceId);

EXPECT_EQ(cell.getInterfaceCount(), 4);
EXPECT_EQ(cell.getInterfaceCount(0), 1);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 4);

const auto originalEdge0InterfaceId = cell.getInterface(0, 0);

// Delete interface reference from the cell.
cell.deleteInterface(0, 0);
EXPECT_EQ(cell.getInterfaceCount(), 3);
EXPECT_EQ(cell.getInterfaceCount(0), 0);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 4);

// Delete the actual V0 to V1 Interface from the shell.
surface->deleteInterface(originalEdge0InterfaceId);
EXPECT_EQ(cell.getInterfaceCount(), 3);
EXPECT_EQ(cell.getInterfaceCount(0), 0);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 3);

// Create the two new interfaces, v0-vX, vX-v1

// 1) Create v0 to vX
auto interfaceV0VXIt = surface->addInterface(bitpit::ElementType::LINE, {v0It->getId(), vXIt->getId()});
interfaceV0VXIt->setOwner(faceId, 0);
EXPECT_EQ(cell.getInterfaceCount(), 3);
EXPECT_EQ(cell.getInterfaceCount(0), 0);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 4);

// 2) Create vX to v1
auto interfaceVXV1It = surface->addInterface(bitpit::ElementType::LINE, {vXIt->getId(), v1It->getId()});
interfaceVXV1It->setOwner(faceId, 0);
EXPECT_EQ(cell.getInterfaceCount(), 3);
EXPECT_EQ(cell.getInterfaceCount(0), 0);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 5);

cell.pushInterface(0, interfaceV0VXIt.getId());
EXPECT_EQ(cell.getInterfaceCount(), 4);
EXPECT_EQ(cell.getInterfaceCount(0), 1);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 5);

cell.pushInterface(0, interfaceVXV1It.getId());
EXPECT_EQ(cell.getInterfaceCount(), 5);
EXPECT_EQ(cell.getInterfaceCount(0), 2);
EXPECT_EQ(cell.getInterfaceCount(1), 1);
EXPECT_EQ(cell.getInterfaceCount(2), 1);
EXPECT_EQ(cell.getInterfaceCount(3), 1);
EXPECT_EQ(surface->getInterfaceCount(), 5);

}

`

I've been looking into this. Looks like everything is working ok but the interfaces on the surface and on each face (cell) are not connected i.e. operations must be done jointly with both.

I've added a thorough test I used to get my head around exactly what's happening but long story short, any interfaces added or removed on the shell should also be updated w/ the affected cells.

Thanks,
Denis

NOTE Initial test case/ reproducer is INVALID. Corresponding cell should be manually updated too.

The functions addInterface/deleteInterface will only create/delete the interface element without updating cell information. Usually, we let SurfUnstructured handle the interfaces automatically. After calling the update method, SurfUnstructured should create all the interface among cells faces. If this is not the case, that's something I can look at.

Manual creation of interfaces is something we don't fully support. I think it can be done, but you need to take care of both interface and cell creation/update. To make things more explicit, we can make the methods addInterface/deleteInterface protected. They are currently public to allow more flexibility, but this may just be confusing.

Are you creating interfaces manually because SurfUnstructured is not handling interface creation properly or because you need additional non-standard interfaces?

Makes sense, these were my findings after digging into the code for some time.

That may be a good idea. My assumption was calling addInterface with the correct params would update the corresponding cells too.

What I'm looking to do is fixup hanging edges on the surface.

// Case 1 :      
//////////////// 
//  c1 //  c2 // 
// --> // --> // 
//////////////// 
//  <-------  // 
//            // 
//////////////// 

In the diagram above, the dashed lines represent the created interfaces, those three are all border interfaces and what I'm looking to do is detect these which we can do and then update by removing that parent interface, passing the correct neighbour with neighbour face to both the child interfaces and then updating that edge on the parent cell.

After these steps I don't require any findNeighbour logic etc and only need to look at interfaces on both the shell and all of the individual cells so I think this should be a good approach.

What do you think?