added: multi-patch model generator for 2D and 3D

This commit is contained in:
Arne Morten Kvarving 2016-09-02 17:22:51 +02:00 committed by Knut Morten Okstad
parent a410d4abb9
commit 66d33ff9e5
3 changed files with 1445 additions and 0 deletions

View File

@ -0,0 +1,463 @@
// $Id$
//==============================================================================
//!
//! \file MultiPatchModelGenerator.C
//!
//! \date Sep 2 2016
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Multi-patch model generators for NURBS-based FEM simulators.
//!
//==============================================================================
#include "MultiPatchModelGenerator.h"
#include "ASMs2D.h"
#include "ASMs3D.h"
#include "IFEM.h"
#include "SIMbase.h"
#include "Utilities.h"
#include "Vec3.h"
#include "Vec3Oper.h"
#include "tinyxml.h"
MultiPatchModelGenerator2D::MultiPatchModelGenerator2D (const TiXmlElement* geo) :
ModelGenerator(geo)
{
nx = ny = 1;
periodic_x = periodic_y = 0;
utl::getAttribute(geo,"nx",nx);
utl::getAttribute(geo,"ny",ny);
utl::getAttribute(geo,"periodic_x", periodic_x);
utl::getAttribute(geo,"periodic_y", periodic_y);
}
std::string MultiPatchModelGenerator2D::createG2 (int nsd) const
{
bool rational=false;
utl::getAttribute(geo,"rational",rational);
if (rational)
IFEM::cout << "\t Rational basis\n";
double scale = 1.0;
if (utl::getAttribute(geo,"scale",scale))
IFEM::cout <<" Scale: "<< scale << std::endl;
double Lx = 1.0, Ly = 1.0;
if (utl::getAttribute(geo,"Lx",Lx))
IFEM::cout <<" Length in X: "<< Lx << std::endl;
Lx *= scale;
if (utl::getAttribute(geo,"Ly",Ly))
IFEM::cout <<" Length in Y: "<< Ly << std::endl;
Ly *= scale;
Vec3 X0;
std::string corner;
if (utl::getAttribute(geo,"X0",corner)) {
std::stringstream str(corner); str >> X0;
IFEM::cout <<" Corner: "<< X0 << std::endl;
}
int nx = 1;
int ny = 1;
if (utl::getAttribute(geo,"nx",nx))
IFEM::cout << " Split in X: " << nx << std::endl;
if (utl::getAttribute(geo,"ny",ny))
IFEM::cout << " Split in Y: " << ny << std::endl;
if (nx > 1)
Lx /= nx;
if (ny > 1)
Ly /= ny;
std::string g2;
for (int y = 0; y < ny; ++y) {
for (int x = 0; x < nx; ++x) {
g2.append("200 1 0 0\n");
g2.append(nsd > 2 ? "3" : "2");
g2.append(rational?" 1":" 0");
g2.append("\n2 2\n0 0 1 1\n2 2\n0 0 1 1");
std::stringstream str;
str <<"\n"<< X0.x+x*Lx <<" "<< X0.y+y*Ly;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
str.str("");
str <<"\n"<< X0.x+(x+1)*Lx <<" "<< X0.y+y*Ly;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
str.str("");
str <<"\n"<< X0.x+x*Lx <<" "<< X0.y+(y+1)*Ly;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
str.str("");
str <<"\n"<< X0.x+(x+1)*Lx <<" "<< X0.y+(y+1)*Ly;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
g2.append("\n");
}
}
return g2;
}
SIMdependency::PatchVec
MultiPatchModelGenerator2D::createGeometry (const SIMbase& sim) const
{
std::istringstream rect(this->createG2(sim.getNoSpaceDim()));
SIMdependency::PatchVec result;
sim.readPatches(rect,result,"\t");
return result;
}
bool MultiPatchModelGenerator2D::createTopology (SIMbase& sim) const
{
auto&& IJ = [this](int i, int j) { return 1 + j*nx + i; };
for (int j = 0; j < ny; ++j)
for (int i = 0; i < nx-1; ++i)
if (!sim.addConnection(IJ(i,j), IJ(i+1,j), 2, 1, 0))
return false;
for (int j = 0; j < ny-1; ++j)
for (int i = 0; i < nx; ++i)
if (!sim.addConnection(IJ(i,j), IJ(i,j+1), 4, 3, 0))
return false;
if (periodic_x)
for (int i = 0; i < ny; ++i)
if (nx > 1) {
if (!sim.addConnection(IJ(0, i), IJ(nx-1, i), 1, 2, 0, false))
return false;
} else {
IFEM::cout <<"\tPeriodic I-direction P"<< IJ(0,i) << std::endl;
ASMs2D* pch = dynamic_cast<ASMs2D*>(sim.getPatch(IJ(0,i), true));
if (pch)
pch->closeEdges(1);
}
if (periodic_y)
for (int i = 0; i < nx; ++i)
if (ny > 1)
if (!sim.addConnection(IJ(i,0), IJ(i,ny-1), 3, 4, 0, false))
return false;
else {
IFEM::cout <<"\tPeriodic J-direction P"<< IJ(i,0)<< std::endl;
ASMs2D* pch = dynamic_cast<ASMs2D*>(sim.getPatch(IJ(i,0), true));
if (pch)
pch->closeEdges(2);
}
return true;
}
TopologySet
MultiPatchModelGenerator2D::createTopologySets (const SIMbase& sim) const
{
if (!sets)
return TopologySet();
TopologySet result;
TopEntity& e1 = result["Edge1"];
TopEntity& e2 = result["Edge2"];
TopEntity& e3 = result["Edge3"];
TopEntity& e4 = result["Edge4"];
TopEntity& e5 = result["Boundary"];
auto&& insertion = [&sim, &e5](TopEntity& e, TopItem top)
{
if ((top.patch = sim.getLocalPatchIndex(top.patch)) > 0) {
e.insert(top);
e5.insert(top);
}
};
for (int i = 0; i < ny; ++i) {
insertion(e1, TopItem(i*nx+1,1,1));
insertion(e2, TopItem((i+1)*nx,2,1));
}
for (int i = 0; i < nx; ++i) {
insertion(e3, TopItem(i+1,3,1));
insertion(e4, TopItem(nx*(ny-1)+1+i,4,1));
}
TopEntity& c = result["Corners"];
auto&& insertionv = [&sim, &c](TopEntity& e, TopItem top)
{
if ((top.patch = sim.getLocalPatchIndex(top.patch)) > 0) {
e.insert(top);
c.insert(top);
}
};
insertionv(result["Vertex1"], TopItem(1,1,0));
insertionv(result["Vertex2"], TopItem(nx,2,0));
insertionv(result["Vertex3"], TopItem(nx*(ny-1)+1,3,0));
insertionv(result["Vertex4"], TopItem(nx*ny,4,0));
return result;
}
MultiPatchModelGenerator3D::MultiPatchModelGenerator3D (const TiXmlElement* geo) :
ModelGenerator(geo)
{
nx = ny = nz = 1;
periodic_x = periodic_y = periodic_z = 0;
utl::getAttribute(geo,"nx",nx);
utl::getAttribute(geo,"ny",ny);
utl::getAttribute(geo,"nz",nz);
utl::getAttribute(geo,"periodic_x", periodic_x);
utl::getAttribute(geo,"periodic_y", periodic_y);
utl::getAttribute(geo,"periodic_z", periodic_z);
}
std::string MultiPatchModelGenerator3D::createG2 (int) const
{
bool rational = false;
utl::getAttribute(geo,"rational",rational);
if (rational)
IFEM::cout <<" Rational basis"<< std::endl;
double scale = 1.0;
if (utl::getAttribute(geo,"scale",scale))
IFEM::cout <<" Scale: "<< scale << std::endl;
double Lx = 1.0, Ly = 1.0, Lz = 1.0;
if (utl::getAttribute(geo,"Lx",Lx))
IFEM::cout <<" Length in X: "<< Lx << std::endl;
Lx *= scale;
if (utl::getAttribute(geo,"Ly",Ly))
IFEM::cout <<" Length in Y: "<< Ly << std::endl;
Ly *= scale;
if (utl::getAttribute(geo,"Lz",Lz))
IFEM::cout <<" Length in Z: "<< Lz << std::endl;
Lz *= scale;
int nx = 1;
int ny = 1;
int nz = 1;
if (utl::getAttribute(geo,"nx",nx))
IFEM::cout << " Split in X: " << nx << std::endl;
if (utl::getAttribute(geo,"ny",ny))
IFEM::cout << " Split in Y: " << ny << std::endl;
if (utl::getAttribute(geo,"nz",nz))
IFEM::cout << " Split in Z: " << nz << std::endl;
Lx /= nx;
Ly /= ny;
Lz /= nz;
std::string corner;
Vec3 X0;
if (utl::getAttribute(geo,"X0",corner)) {
std::stringstream str(corner);
str >> X0;
IFEM::cout <<" Corner: "<< X0 << std::endl;
}
std::array<double,24> nodes =
{{ 0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
1.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0,
0.0, 1.0, 1.0,
1.0, 1.0, 1.0 }};
std::string g2;
for (int z = 0; z < nz; ++z) {
for (int y = 0; y < ny; ++y) {
for (int x = 0; x < nx; ++x) {
g2.append("700 1 0 0\n3 ");
g2.append(rational ? "1\n" : "0\n");
g2.append("2 2\n0 0 1 1\n"
"2 2\n0 0 1 1\n"
"2 2\n0 0 1 1\n");
for (size_t i = 0; i < nodes.size(); i += 3)
{
std::stringstream str;
std::array<int,3> N {x,y,z};
std::array<double,3> L {Lx,Ly,Lz};
for (size_t j = 0; j < 3; j++)
str << (j==0?"":" ") << X0[j]+N[j]*L[j]+nodes[i+j]*L[j];
g2.append(str.str());
g2.append(rational ? " 1.0\n" : "\n");
}
}
}
}
return g2;
}
SIMdependency::PatchVec
MultiPatchModelGenerator3D::createGeometry (const SIMbase& sim) const
{
std::istringstream hex(this->createG2(sim.getNoSpaceDim()));
SIMdependency::PatchVec result;
sim.readPatches(hex,result,"\t");
return result;
}
bool MultiPatchModelGenerator3D::createTopology (SIMbase& sim) const
{
auto&& IJK = [this](int i, int j, int k) { return 1 + (k*ny+j)*nx + i; };
for (int k = 0; k < nz; ++k)
for (int j = 0; j < ny; ++j)
for (int i = 0; i < nx-1; ++i)
if (!sim.addConnection(IJK(i,j,k), IJK(i+1,j,k), 2, 1, 0))
return false;
for (int k = 0; k < nz; ++k)
for (int j = 0; j < ny-1; ++j)
for (int i = 0; i < nx; ++i)
if (!sim.addConnection(IJK(i,j,k), IJK(i,j+1,k), 4, 3, 0))
return false;
for (int k = 0; k < nz-1; ++k)
for (int j = 0; j < ny; ++j)
for (int i = 0; i < nx; ++i)
if (!sim.addConnection(IJK(i,j,k), IJK(i,j,k+1), 6, 5, 0))
return false;
if (periodic_x)
for (int k = 0; k < nz; ++k)
for (int j = 0; j < ny; ++j)
if (nx > 1) {
if (!sim.addConnection(IJK(0,j,k), IJK(nx-1,j,k), 1, 2, 0, false))
return false;
} else {
IFEM::cout <<"\tPeriodic I-direction P"<< IJK(0,j,k) << std::endl;
ASMs3D* pch = dynamic_cast<ASMs3D*>(sim.getPatch(IJK(0,j,k), true));
if (pch)
pch->closeFaces(1);
}
if (periodic_y)
for (int k = 0; k < nz; ++k)
for (int i = 0; i < nx; ++i)
if (ny > 1) {
if (!sim.addConnection(IJK(i,0,k), IJK(i,ny-1,k), 3, 4, 0, false))
return false;
} else {
IFEM::cout <<"\tPeriodic J-direction P"<< IJK(i,0,k) << std::endl;
ASMs3D* pch = dynamic_cast<ASMs3D*>(sim.getPatch(IJK(i,0,k), true));
if (pch)
pch->closeFaces(2);
}
if (periodic_z)
for (int j = 0; j < ny; ++j)
for (int i = 0; i < nx; ++i)
if (nz > 1) {
if (!sim.addConnection(IJK(i,j,0), IJK(i,j,nz-1), 5, 6, 0, false))
return false;
} else {
IFEM::cout <<"\tPeriodic K-direction P"<< IJK(i,j,0) << std::endl;
ASMs3D* pch = dynamic_cast<ASMs3D*>(sim.getPatch(IJK(i,j,0), true));
if (pch)
pch->closeFaces(3);
}
return true;
}
TopologySet
MultiPatchModelGenerator3D::createTopologySets (const SIMbase& sim) const
{
if (!sets)
return TopologySet();
// 0-based -> 1-based IJK
auto&& IJK = [this](int i, int j, int k) { return 1 + (k*ny+j)*nx + i; };
// start/end IJK
auto&& IJK2 = [this,IJK](int i, int j, int k) { return IJK(i*(nx-1), j*(ny-1), k*(nz-1)); };
// start/end JK
auto&& IJKI = [this,IJK](int i, int j, int k) { return IJK(i, j*(ny-1), k*(nz-1)); };
// start/end IK
auto&& IJKJ = [this,IJK](int i, int j, int k) { return IJK(i*(nx-1), j, k*(nz-1)); };
// start/end IJ
auto&& IJKK = [this,IJK](int i, int j, int k) { return IJK(i*(nx-1), j*(ny-1), k); };
// start/end I
auto&& IJK2I = [this,IJK](int i, int j, int k) { return IJK(i*(nx-1), j, k); };
// start/end J
auto&& IJK2J = [this,IJK](int i, int j, int k) { return IJK(i, j*(ny-1), k); };
// start/end K
auto&& IJK2K = [this,IJK](int i, int j, int k) { return IJK(i, j, k*(nz-1)); };
TopologySet result;
// insertion lambda
auto&& insertion = [&sim,&result](TopItem top,
const std::string& glob,
const std::string& type)
{
std::stringstream str;
str << type << top.item;
TopEntity& topI = result[str.str()];
TopEntity& globI = result[glob];
if ((top.patch = sim.getLocalPatchIndex(top.patch)) > 0) {
topI.insert(top);
globI.insert(top);
}
};
size_t r = 1;
for (int i = 0; i < 2; ++i, ++r)
for (int k = 0; k < nz; ++k)
for (int j = 0; j < ny; ++j)
insertion(TopItem(IJK2I(i,j,k),r,2), "Boundary", "Face");
for (int j = 0; j < 2; ++j, ++r)
for (int k = 0; k < nz; ++k)
for (int i = 0; i < nx; ++i)
insertion(TopItem(IJK2J(i,j,k),r,2), "Boundary", "Face");
for (int k = 0; k < 2; ++k, ++r)
for (int j = 0; j < ny; ++j)
for (int i = 0; i < nx; ++i)
insertion(TopItem(IJK2K(i,j,k),r,2), "Boundary", "Face");
r = 1;
for (int k = 0; k < 2; ++k)
for (int j = 0; j < 2; ++j)
for (int i = 0; i < 2; ++i, ++r)
insertion(TopItem(IJK2(i,j,k),r,0), "Corners", "Vertex");
r = 1;
for (int k = 0; k < 2; ++k)
for (int i = 0; i < 2; ++i, ++r)
for (int j = 0; j < ny; ++j)
insertion(TopItem(IJKJ(i,j,k),r,1), "Frame", "Edge");
for (int j = 0; j < 2; ++j)
for (int i = 0; i < 2; ++i, ++r)
for (int k = 0; k < nz; ++k)
insertion(TopItem(IJKK(i,j,k),r,1), "Frame", "Edge");
for (int k = 0; k < 2; ++k)
for (int j = 0; j < 2; ++j, ++r)
for (int i = 0; i < nx; ++i)
insertion(TopItem(IJKI(i,j,k),r,1), "Frame", "Edge");
return result;
}

View File

@ -0,0 +1,100 @@
// $Id$
//==============================================================================
//!
//! \file MultiPatchModelGenerator.h
//!
//! \date Sep 2 2016
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Multi-patch model generators for NURBS-based FEM simulators.
//!
//==============================================================================
#ifndef _MULTIPATCH_MODEL_GENERATOR_H
#define _MULTIPATCH_MODEL_GENERATOR_H
#include "ModelGenerator.h"
#include <string>
/*!
\brief 2D multi-patch model generator for FEM simulators.
\details Generate a rectangle split in a given number of blocks.
*/
class MultiPatchModelGenerator2D : public ModelGenerator
{
public:
//! \brief Constructor initializes common members.
//!\ param[in] elem XML element to parse
MultiPatchModelGenerator2D(const TiXmlElement* elem);
//! \brief Empty destructor.
virtual ~MultiPatchModelGenerator2D() {}
//! \brief Creates a geometry.
//! \param[in] sim SIM with patch read function to use
SIMdependency::PatchVec createGeometry(const SIMbase& sim) const override;
//! \brief Creates topology for geometry.
//! \param sim Simulator to apply topology to
bool createTopology(SIMbase& sim) const override;
//! \brief Creates topology sets for geometry.
TopologySet createTopologySets(const SIMbase& sim) const override;
protected:
//! \brief Generates the G2 description of the geometry.
//! \param nsd Number of spatial dimension
std::string createG2 (int nsd = 2) const;
int nx; //!< Number of blocks in x
int ny; //!< Number of blocks in y
int periodic_x; //!< If non-zero, make model periodic in x for given bases
int periodic_y; //!< If non-zero, make model periodic in y for given bases
};
/*!
\brief 3D multi-patch model generator for FEM simulators.
\details Generates a hexahedra split in a given number of blocks.
*/
class MultiPatchModelGenerator3D : public ModelGenerator
{
public:
//! \brief Constructor initializes common members.
//! \param[in] elem XML element to parse
MultiPatchModelGenerator3D(const TiXmlElement* geo);
//! \brief Empty destructor.
virtual ~MultiPatchModelGenerator3D() {}
//! \brief Creates a geometry.
//! \param[in] sim SIM with patch read function to use
SIMdependency::PatchVec createGeometry(const SIMbase& sim) const override;
//! \brief Creates topology for geometry.
//! \param[in] geo XML element containing geometry defintion
//! \param sim Simulator to apply topology to
bool createTopology(SIMbase& sim) const override;
//! \brief Creates topology sets for geometry.
//! \param[in] SIM Simulator with patch ownerships
virtual TopologySet createTopologySets(const SIMbase& sim) const;
protected:
//! \brief Generates the G2 description of the geometry.
//! \param nsd Number of spatial dimension
std::string createG2 (int nsd = 3) const;
int nx; //!< Number of blocks in x
int ny; //!< Number of blocks in y
int nz; //!< Number of blocks in z
int periodic_x; //!< If non-zero, make model periodic in x for given bases
int periodic_y; //!< If non-zero, make model periodic in y for given bases
int periodic_z; //!< If non-zero, make model periodic in z for given bases
};
#endif

View File

@ -0,0 +1,882 @@
//==============================================================================
//!
//! \file TestMultiPatchModelGenerator.C
//!
//! \date Sep 2 2016
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Tests for multi-patch model generators.
//!
//==============================================================================
#include "IFEM.h"
#include "MultiPatchModelGenerator.h"
#include "SIM2D.h"
#include "SIM3D.h"
#include "TopologySet.h"
#include "gtest/gtest.h"
#include "tinyxml.h"
template<class Generator>
class TestModelGeneratorWrapper : public Generator {
public:
TestModelGeneratorWrapper(const TiXmlElement* geo) : Generator(geo) {}
std::string createG2(int nsd)
{
return Generator::createG2(nsd);
}
};
struct GeomTest {
std::string xml;
int dim;
std::string g2;
std::string sets;
};
class TestMultiPatchModelGenerator1D :
public testing::Test,
public testing::WithParamInterface<GeomTest>
{
};
class TestMultiPatchModelGenerator2D :
public testing::Test,
public testing::WithParamInterface<GeomTest>
{
};
class TestMultiPatchModelGenerator3D :
public testing::Test,
public testing::WithParamInterface<GeomTest>
{
};
auto&& DoTest = [](const GeomTest& ref, const std::string& gen,
const TopologySet& sets)
{
ASSERT_STREQ(gen.c_str(), ref.g2.c_str());
if (!ref.sets.empty()) {
std::string gsets;
for (auto& it : sets) {
gsets += it.first + ": ";
for (auto& it2 : it.second) {
std::stringstream str;
str << it2.patch << " " << it2.item << " " << it2.idim << " ";
gsets += str.str();
}
gsets += "\n";
}
ASSERT_STREQ(gsets.c_str(), ref.sets.c_str());
}
};
TEST_P(TestMultiPatchModelGenerator2D, Generate)
{
TiXmlDocument doc;
doc.Parse(GetParam().xml.c_str());
TestModelGeneratorWrapper<MultiPatchModelGenerator2D> gen(doc.RootElement());
std::string g2 = gen.createG2(GetParam().dim);
SIM2D sim;
TopologySet sets = gen.createTopologySets(sim);
DoTest(GetParam(), g2, sets);
}
TEST_P(TestMultiPatchModelGenerator3D, Generate)
{
TiXmlDocument doc;
doc.Parse(GetParam().xml.c_str());
TestModelGeneratorWrapper<MultiPatchModelGenerator3D> gen(doc.RootElement());
std::string g2 = gen.createG2(GetParam().dim);
SIM3D sim;
TopologySet sets = gen.createTopologySets(sim);
DoTest(GetParam(), g2, sets);
}
const std::vector<GeomTest> geometry2D =
{{"<geometry sets=\"true\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"1 0\n"
"0 1\n"
"1 1\n",
"Boundary: 1 1 1 1 2 1 1 3 1 1 4 1 \n"
"Corners: 1 1 0 1 2 0 1 3 0 1 4 0 \n"
"Edge1: 1 1 1 \n"
"Edge2: 1 2 1 \n"
"Edge3: 1 3 1 \n"
"Edge4: 1 4 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"
"Vertex3: 1 3 0 \n"
"Vertex4: 1 4 0 \n"},
{"<geometry rational=\"1\"/>", 2,
"200 1 0 0\n"
"2 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 1.0\n"
"1 0 1.0\n"
"0 1 1.0\n"
"1 1 1.0\n", ""},
{"<geometry scale=\"2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"2 0\n"
"0 2\n"
"2 2\n", ""},
{"<geometry X0=\"2 0\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 0\n"
"3 0\n"
"2 1\n"
"3 1\n"},
{"<geometry X0=\"0 2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 2\n"
"1 2\n"
"0 3\n"
"1 3\n", ""},
{"<geometry Lx=\"2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"2 0\n"
"0 1\n"
"2 1\n", ""},
{"<geometry Ly=\"2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"1 0\n"
"0 2\n"
"1 2\n", ""},
{"<geometry sets=\"true\" nx=\"2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"0.5 0\n"
"0 1\n"
"0.5 1\n"
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0\n"
"1 0\n"
"0.5 1\n"
"1 1\n",
"Boundary: 1 1 1 1 3 1 1 4 1 2 2 1 2 3 1 2 4 1 \n"
"Corners: 1 1 0 1 3 0 2 2 0 2 4 0 \n"
"Edge1: 1 1 1 \n"
"Edge2: 2 2 1 \n"
"Edge3: 1 3 1 2 3 1 \n"
"Edge4: 1 4 1 2 4 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 2 2 0 \n"
"Vertex3: 1 3 0 \n"
"Vertex4: 2 4 0 \n"},
{"<geometry sets=\"true\" ny=\"2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"1 0\n"
"0 0.5\n"
"1 0.5\n"
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0.5\n"
"1 0.5\n"
"0 1\n"
"1 1\n",
"Boundary: 1 1 1 1 2 1 1 3 1 2 1 1 2 2 1 2 4 1 \n"
"Corners: 1 1 0 1 2 0 2 3 0 2 4 0 \n"
"Edge1: 1 1 1 2 1 1 \n"
"Edge2: 1 2 1 2 2 1 \n"
"Edge3: 1 3 1 \n"
"Edge4: 2 4 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"
"Vertex3: 2 3 0 \n"
"Vertex4: 2 4 0 \n"},
{"<geometry sets=\"true\" nx=\"2\" ny=\"2\"/>", 2,
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0\n"
"0.5 0\n"
"0 0.5\n"
"0.5 0.5\n"
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0\n"
"1 0\n"
"0.5 0.5\n"
"1 0.5\n"
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0.5\n"
"0.5 0.5\n"
"0 1\n"
"0.5 1\n"
"200 1 0 0\n"
"2 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0.5\n"
"1 0.5\n"
"0.5 1\n"
"1 1\n",
"Boundary: 1 1 1 1 3 1 2 2 1 2 3 1 3 1 1 3 4 1 4 2 1 4 4 1 \n"
"Corners: 1 1 0 2 2 0 3 3 0 4 4 0 \n"
"Edge1: 1 1 1 3 1 1 \n"
"Edge2: 2 2 1 4 2 1 \n"
"Edge3: 1 3 1 2 3 1 \n"
"Edge4: 3 4 1 4 4 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 2 2 0 \n"
"Vertex3: 3 3 0 \n"
"Vertex4: 4 4 0 \n"}};
INSTANTIATE_TEST_CASE_P(TestMultiPatchModelGenerator2D,
TestMultiPatchModelGenerator2D,
testing::ValuesIn(geometry2D));
const std::vector<GeomTest> geometry3D =
{{"<geometry sets=\"true\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"1 0 0\n"
"0 1 0\n"
"1 1 0\n"
"0 0 1\n"
"1 0 1\n"
"0 1 1\n"
"1 1 1\n",
"Boundary: 1 1 2 1 2 2 1 3 2 1 4 2 1 5 2 1 6 2 \n"
"Corners: 1 1 0 1 2 0 1 3 0 1 4 0 1 5 0 1 6 0 1 7 0 1 8 0 \n"
"Edge1: 1 1 1 \n"
"Edge10: 1 10 1 \n"
"Edge11: 1 11 1 \n"
"Edge12: 1 12 1 \n"
"Edge2: 1 2 1 \n"
"Edge3: 1 3 1 \n"
"Edge4: 1 4 1 \n"
"Edge5: 1 5 1 \n"
"Edge6: 1 6 1 \n"
"Edge7: 1 7 1 \n"
"Edge8: 1 8 1 \n"
"Edge9: 1 9 1 \n"
"Face1: 1 1 2 \n"
"Face2: 1 2 2 \n"
"Face3: 1 3 2 \n"
"Face4: 1 4 2 \n"
"Face5: 1 5 2 \n"
"Face6: 1 6 2 \n"
"Frame: 1 1 1 1 2 1 1 3 1 1 4 1 1 5 1 1 6 1 1 7 1 1 8 1 1 9 1 1 10 1 1 11 1 1 12 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"
"Vertex3: 1 3 0 \n"
"Vertex4: 1 4 0 \n"
"Vertex5: 1 5 0 \n"
"Vertex6: 1 6 0 \n"
"Vertex7: 1 7 0 \n"
"Vertex8: 1 8 0 \n"},
{"<geometry rational=\"1\"/>", 3,
"700 1 0 0\n"
"3 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0 1.0\n"
"1 0 0 1.0\n"
"0 1 0 1.0\n"
"1 1 0 1.0\n"
"0 0 1 1.0\n"
"1 0 1 1.0\n"
"0 1 1 1.0\n"
"1 1 1 1.0\n", ""},
{"<geometry scale=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"2 0 0\n"
"0 2 0\n"
"2 2 0\n"
"0 0 2\n"
"2 0 2\n"
"0 2 2\n"
"2 2 2\n", ""},
{"<geometry X0=\"2 0 0\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 0 0\n"
"3 0 0\n"
"2 1 0\n"
"3 1 0\n"
"2 0 1\n"
"3 0 1\n"
"2 1 1\n"
"3 1 1\n", ""},
{"<geometry X0=\"0 2 0\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 2 0\n"
"1 2 0\n"
"0 3 0\n"
"1 3 0\n"
"0 2 1\n"
"1 2 1\n"
"0 3 1\n"
"1 3 1\n", ""},
{"<geometry X0=\"0 0 2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 2\n"
"1 0 2\n"
"0 1 2\n"
"1 1 2\n"
"0 0 3\n"
"1 0 3\n"
"0 1 3\n"
"1 1 3\n", ""},
{"<geometry Lx=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"2 0 0\n"
"0 1 0\n"
"2 1 0\n"
"0 0 1\n"
"2 0 1\n"
"0 1 1\n"
"2 1 1\n", ""},
{"<geometry Ly=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"1 0 0\n"
"0 2 0\n"
"1 2 0\n"
"0 0 1\n"
"1 0 1\n"
"0 2 1\n"
"1 2 1\n", ""},
{"<geometry Lz=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"1 0 0\n"
"0 1 0\n"
"1 1 0\n"
"0 0 2\n"
"1 0 2\n"
"0 1 2\n"
"1 1 2\n", ""},
{"<geometry sets=\"true\" nx=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"0.5 0 0\n"
"0 1 0\n"
"0.5 1 0\n"
"0 0 1\n"
"0.5 0 1\n"
"0 1 1\n"
"0.5 1 1\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0 0\n"
"1 0 0\n"
"0.5 1 0\n"
"1 1 0\n"
"0.5 0 1\n"
"1 0 1\n"
"0.5 1 1\n"
"1 1 1\n",
"Boundary: 1 1 2 1 3 2 1 4 2 1 5 2 1 6 2 2 2 2 2 3 2 2 4 2 2 5 2 2 6 2 \n"
"Corners: 1 1 0 1 3 0 1 5 0 1 7 0 2 2 0 2 4 0 2 6 0 2 8 0 \n"
"Edge1: 1 1 1 \n"
"Edge10: 1 10 1 2 10 1 \n"
"Edge11: 1 11 1 2 11 1 \n"
"Edge12: 1 12 1 2 12 1 \n"
"Edge2: 2 2 1 \n"
"Edge3: 1 3 1 \n"
"Edge4: 2 4 1 \n"
"Edge5: 1 5 1 \n"
"Edge6: 2 6 1 \n"
"Edge7: 1 7 1 \n"
"Edge8: 2 8 1 \n"
"Edge9: 1 9 1 2 9 1 \n"
"Face1: 1 1 2 \n"
"Face2: 2 2 2 \n"
"Face3: 1 3 2 2 3 2 \n"
"Face4: 1 4 2 2 4 2 \n"
"Face5: 1 5 2 2 5 2 \n"
"Face6: 1 6 2 2 6 2 \n"
"Frame: 1 1 1 1 3 1 1 5 1 1 7 1 1 9 1 1 10 1 1 11 1 1 12 1 2 2 1 2 4 1 2 6 1 2 8 1 2 9 1 2 10 1 2 11 1 2 12 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 2 2 0 \n"
"Vertex3: 1 3 0 \n"
"Vertex4: 2 4 0 \n"
"Vertex5: 1 5 0 \n"
"Vertex6: 2 6 0 \n"
"Vertex7: 1 7 0 \n"
"Vertex8: 2 8 0 \n"},
{"<geometry sets=\"true\" ny=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"1 0 0\n"
"0 0.5 0\n"
"1 0.5 0\n"
"0 0 1\n"
"1 0 1\n"
"0 0.5 1\n"
"1 0.5 1\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0.5 0\n"
"1 0.5 0\n"
"0 1 0\n"
"1 1 0\n"
"0 0.5 1\n"
"1 0.5 1\n"
"0 1 1\n"
"1 1 1\n",
"Boundary: 1 1 2 1 2 2 1 3 2 1 5 2 1 6 2 2 1 2 2 2 2 2 4 2 2 5 2 2 6 2 \n"
"Corners: 1 1 0 1 2 0 1 5 0 1 6 0 2 3 0 2 4 0 2 7 0 2 8 0 \n"
"Edge1: 1 1 1 2 1 1 \n"
"Edge10: 2 10 1 \n"
"Edge11: 1 11 1 \n"
"Edge12: 2 12 1 \n"
"Edge2: 1 2 1 2 2 1 \n"
"Edge3: 1 3 1 2 3 1 \n"
"Edge4: 1 4 1 2 4 1 \n"
"Edge5: 1 5 1 \n"
"Edge6: 1 6 1 \n"
"Edge7: 2 7 1 \n"
"Edge8: 2 8 1 \n"
"Edge9: 1 9 1 \n"
"Face1: 1 1 2 2 1 2 \n"
"Face2: 1 2 2 2 2 2 \n"
"Face3: 1 3 2 \n"
"Face4: 2 4 2 \n"
"Face5: 1 5 2 2 5 2 \n"
"Face6: 1 6 2 2 6 2 \n"
"Frame: 1 1 1 1 2 1 1 3 1 1 4 1 1 5 1 1 6 1 1 9 1 1 11 1 2 1 1 2 2 1 2 3 1 2 4 1 2 7 1 2 8 1 2 10 1 2 12 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"
"Vertex3: 2 3 0 \n"
"Vertex4: 2 4 0 \n"
"Vertex5: 1 5 0 \n"
"Vertex6: 1 6 0 \n"
"Vertex7: 2 7 0 \n"
"Vertex8: 2 8 0 \n"},
{"<geometry sets=\"true\" nz=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"1 0 0\n"
"0 1 0\n"
"1 1 0\n"
"0 0 0.5\n"
"1 0 0.5\n"
"0 1 0.5\n"
"1 1 0.5\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0.5\n"
"1 0 0.5\n"
"0 1 0.5\n"
"1 1 0.5\n"
"0 0 1\n"
"1 0 1\n"
"0 1 1\n"
"1 1 1\n",
"Boundary: 1 1 2 1 2 2 1 3 2 1 4 2 1 5 2 2 1 2 2 2 2 2 3 2 2 4 2 2 6 2 \n"
"Corners: 1 1 0 1 2 0 1 3 0 1 4 0 2 5 0 2 6 0 2 7 0 2 8 0 \n"
"Edge1: 1 1 1 \n"
"Edge10: 1 10 1 \n"
"Edge11: 2 11 1 \n"
"Edge12: 2 12 1 \n"
"Edge2: 1 2 1 \n"
"Edge3: 2 3 1 \n"
"Edge4: 2 4 1 \n"
"Edge5: 1 5 1 2 5 1 \n"
"Edge6: 1 6 1 2 6 1 \n"
"Edge7: 1 7 1 2 7 1 \n"
"Edge8: 1 8 1 2 8 1 \n"
"Edge9: 1 9 1 \n"
"Face1: 1 1 2 2 1 2 \n"
"Face2: 1 2 2 2 2 2 \n"
"Face3: 1 3 2 2 3 2 \n"
"Face4: 1 4 2 2 4 2 \n"
"Face5: 1 5 2 \n"
"Face6: 2 6 2 \n"
"Frame: 1 1 1 1 2 1 1 5 1 1 6 1 1 7 1 1 8 1 1 9 1 1 10 1 2 3 1 2 4 1 2 5 1 2 6 1 2 7 1 2 8 1 2 11 1 2 12 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"
"Vertex3: 1 3 0 \n"
"Vertex4: 1 4 0 \n"
"Vertex5: 2 5 0 \n"
"Vertex6: 2 6 0 \n"
"Vertex7: 2 7 0 \n"
"Vertex8: 2 8 0 \n"},
{"<geometry sets=\"true\" nx=\"2\" ny=\"2\" nz=\"2\"/>", 3,
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0\n"
"0.5 0 0\n"
"0 0.5 0\n"
"0.5 0.5 0\n"
"0 0 0.5\n"
"0.5 0 0.5\n"
"0 0.5 0.5\n"
"0.5 0.5 0.5\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0 0\n"
"1 0 0\n"
"0.5 0.5 0\n"
"1 0.5 0\n"
"0.5 0 0.5\n"
"1 0 0.5\n"
"0.5 0.5 0.5\n"
"1 0.5 0.5\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0.5 0\n"
"0.5 0.5 0\n"
"0 1 0\n"
"0.5 1 0\n"
"0 0.5 0.5\n"
"0.5 0.5 0.5\n"
"0 1 0.5\n"
"0.5 1 0.5\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0.5 0\n"
"1 0.5 0\n"
"0.5 1 0\n"
"1 1 0\n"
"0.5 0.5 0.5\n"
"1 0.5 0.5\n"
"0.5 1 0.5\n"
"1 1 0.5\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0 0.5\n"
"0.5 0 0.5\n"
"0 0.5 0.5\n"
"0.5 0.5 0.5\n"
"0 0 1\n"
"0.5 0 1\n"
"0 0.5 1\n"
"0.5 0.5 1\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0 0.5\n"
"1 0 0.5\n"
"0.5 0.5 0.5\n"
"1 0.5 0.5\n"
"0.5 0 1\n"
"1 0 1\n"
"0.5 0.5 1\n"
"1 0.5 1\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0 0.5 0.5\n"
"0.5 0.5 0.5\n"
"0 1 0.5\n"
"0.5 1 0.5\n"
"0 0.5 1\n"
"0.5 0.5 1\n"
"0 1 1\n"
"0.5 1 1\n"
"700 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.5 0.5 0.5\n"
"1 0.5 0.5\n"
"0.5 1 0.5\n"
"1 1 0.5\n"
"0.5 0.5 1\n"
"1 0.5 1\n"
"0.5 1 1\n"
"1 1 1\n",
"Boundary: 1 1 2 1 3 2 1 5 2 "
"2 2 2 2 3 2 2 5 2 "
"3 1 2 3 4 2 3 5 2 "
"4 2 2 4 4 2 4 5 2 "
"5 1 2 5 3 2 5 6 2 "
"6 2 2 6 3 2 6 6 2 "
"7 1 2 7 4 2 7 6 2 "
"8 2 2 8 4 2 8 6 2 \n"
"Corners: 1 1 0 2 2 0 3 3 0 4 4 0 5 5 0 6 6 0 7 7 0 8 8 0 \n"
"Edge1: 1 1 1 3 1 1 \n"
"Edge10: 3 10 1 4 10 1 \n"
"Edge11: 5 11 1 6 11 1 \n"
"Edge12: 7 12 1 8 12 1 \n"
"Edge2: 2 2 1 4 2 1 \n"
"Edge3: 5 3 1 7 3 1 \n"
"Edge4: 6 4 1 8 4 1 \n"
"Edge5: 1 5 1 5 5 1 \n"
"Edge6: 2 6 1 6 6 1 \n"
"Edge7: 3 7 1 7 7 1 \n"
"Edge8: 4 8 1 8 8 1 \n"
"Edge9: 1 9 1 2 9 1 \n"
"Face1: 1 1 2 3 1 2 5 1 2 7 1 2 \n"
"Face2: 2 2 2 4 2 2 6 2 2 8 2 2 \n"
"Face3: 1 3 2 2 3 2 5 3 2 6 3 2 \n"
"Face4: 3 4 2 4 4 2 7 4 2 8 4 2 \n"
"Face5: 1 5 2 2 5 2 3 5 2 4 5 2 \n"
"Face6: 5 6 2 6 6 2 7 6 2 8 6 2 \n"
"Frame: 1 1 1 1 5 1 1 9 1 "
"2 2 1 2 6 1 2 9 1 "
"3 1 1 3 7 1 3 10 1 "
"4 2 1 4 8 1 4 10 1 "
"5 3 1 5 5 1 5 11 1 "
"6 4 1 6 6 1 6 11 1 "
"7 3 1 7 7 1 7 12 1 "
"8 4 1 8 8 1 8 12 1 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 2 2 0 \n"
"Vertex3: 3 3 0 \n"
"Vertex4: 4 4 0 \n"
"Vertex5: 5 5 0 \n"
"Vertex6: 6 6 0 \n"
"Vertex7: 7 7 0 \n"
"Vertex8: 8 8 0 \n"}};
INSTANTIATE_TEST_CASE_P(TestMultiPatchModelGenerator3D,
TestMultiPatchModelGenerator3D,
testing::ValuesIn(geometry3D));