added: A base class for model generators

simple single-patch generators are also included.

this will be used to allow for advanced model generation in applications.
This commit is contained in:
Arne Morten Kvarving 2016-09-02 15:22:21 +02:00 committed by Knut Morten Okstad
parent a5812724a2
commit a410d4abb9
3 changed files with 915 additions and 0 deletions

300
src/SIM/ModelGenerator.C Normal file
View File

@ -0,0 +1,300 @@
// $Id$
//==============================================================================
//!
//! \file ModelGenerator.C
//!
//! \date Sep 2 2016
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Base class for model generators for NURBS-based FEM simulators.
//!
//==============================================================================
#include "ModelGenerator.h"
#include "IFEM.h"
#include "SIMbase.h"
#include "Utilities.h"
#include "Vec3.h"
#include "Vec3Oper.h"
#include "tinyxml.h"
ModelGenerator::ModelGenerator (const TiXmlElement* elem) :
sets(false), geo(elem)
{
utl::getAttribute(geo, "sets", sets);
}
std::string DefaultGeometry1D::createG2 (int nsd) const
{
std::string g2("100 1 0 0\n");
g2.append(1,'0'+nsd);
bool rational=false;
utl::getAttribute(geo,"rational",rational);
if (rational)
IFEM::cout << "\t Rational basis\n";
g2.append(rational?" 1":" 0");
g2.append("\n2 2\n0 0 1 1\n");
unsigned char d;
std::string XYZ;
if (utl::getAttribute(geo,"X0",XYZ))
{
IFEM::cout <<" X0 = "<< XYZ << std::endl;
g2.append(XYZ);
}
else
{
g2.append("0.0");
for (d = 1; d < nsd; d++)
g2.append(" 0.0");
}
if (rational)
g2.append(" 1.0");
g2.append("\n");
if (utl::getAttribute(geo,"X1",XYZ))
{
IFEM::cout <<"\tX1 = "<< XYZ << std::endl;
g2.append(XYZ);
}
else
{
XYZ = "1.0";
if (utl::getAttribute(geo,"L",XYZ))
IFEM::cout <<" Length scale: "<< XYZ << std::endl;
g2.append(XYZ);
for (d = 1; d < nsd; d++)
g2.append(" 0.0");
}
if (rational)
g2.append(" 1.0");
g2.append("\n");
return g2;
}
SIMdependency::PatchVec DefaultGeometry1D::createGeometry (const SIMbase& sim) const
{
std::istringstream unitLine(this->createG2(sim.getNoSpaceDim()));
SIMdependency::PatchVec result;
sim.readPatches(unitLine,result,"\t");
return result;
}
TopologySet DefaultGeometry1D::createTopologySets (const SIMbase&) const
{
if (!sets)
return TopologySet();
TopologySet result;
result["Vertex1"].insert(TopItem(1,1,0));
result["Vertex2"].insert(TopItem(1,2,0));
result["Boundary"].insert(TopItem(1,1,0));
result["Boundary"].insert(TopItem(1,2,0));
result["Corners"].insert(TopItem(1,1,0));
result["Corners"].insert(TopItem(1,2,0));
return result;
}
std::string DefaultGeometry2D::createG2 (int nsd) const
{
std::string g2("200 1 0 0\n");
g2.append(nsd > 2 ? "3" : "2");
bool rational=false;
utl::getAttribute(geo,"rational",rational);
if (rational)
IFEM::cout << "\t Rational basis\n";
g2.append(rational?" 1":" 0");
g2.append("\n2 2\n0 0 1 1\n2 2\n0 0 1 1");
Vec3 X0;
std::string corner;
if (utl::getAttribute(geo,"X0",corner)) {
std::stringstream str(corner); str >> X0;
IFEM::cout <<" Corner: "<< X0 << 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;
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;
std::stringstream str;
str <<"\n"<< X0.x <<" "<< X0.y;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
str.str("");
str <<"\n"<< X0.x+Lx <<" "<< X0.y;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
str.str("");
str <<"\n"<< X0.x <<" "<< X0.y+Ly;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
str.str("");
str <<"\n"<< X0.x+Lx <<" "<< X0.y+Ly;
if (nsd > 2) str <<" 0.0";
if (rational) str << " 1.0";
g2.append(str.str());
g2.append("\n");
return g2;
}
SIMdependency::PatchVec DefaultGeometry2D::createGeometry (const SIMbase& sim) const
{
std::istringstream unitSquare(this->createG2(sim.getNoSpaceDim()));
SIMdependency::PatchVec result;
sim.readPatches(unitSquare,result,"\t");
return result;
}
TopologySet DefaultGeometry2D::createTopologySets (const SIMbase&) const
{
if (!sets)
return TopologySet();
TopologySet result;
std::string vert = "Vertex1";
std::string edge = "Edge1";
for (size_t i = 1; i <= 4; ++i, ++vert.back(), ++edge.back()) {
result[vert].insert(TopItem(1,i,0));
result[edge].insert(TopItem(1,i,1));
result["Corners"].insert(TopItem(1,i,0));
result["Boundary"].insert(TopItem(1,i,1));
}
return result;
}
std::string DefaultGeometry3D::createG2 (int) const
{
std::string g2("700 1 0 0\n3 ");
bool rational = false;
utl::getAttribute(geo,"rational",rational);
if (rational)
IFEM::cout <<" Rational basis"<< std::endl;
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");
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 }};
double scale = 1.0;
if (utl::getAttribute(geo,"scale",scale))
IFEM::cout <<"\tscale = "<< scale << std::endl;
double Lx = 1.0, Ly = 1.0, Lz = 1.0;
if (utl::getAttribute(geo,"Lx",Lx))
IFEM::cout <<"\tLength in X: "<< Lx << std::endl;
Lx *= scale;
if (utl::getAttribute(geo,"Ly",Ly))
IFEM::cout <<"\tLength in Y: "<< Ly << std::endl;
Ly *= scale;
if (utl::getAttribute(geo,"Lz",Lz))
IFEM::cout <<"\tLength in Z: "<< Lz << std::endl;
Lz *= scale;
if (Lx != 1.0)
nodes[3] = nodes[9] = nodes[15] = nodes[21] = Lx;
if (Ly != 1.0)
nodes[7] = nodes[10] = nodes[19] = nodes[22] = Ly;
if (Lz != 1.0)
nodes[14] = nodes[17] = nodes[20] = nodes[23] = Lz;
std::string corner;
if (utl::getAttribute(geo,"X0",corner)) {
std::stringstream str(corner);
Vec3 X0;
str >> X0;
IFEM::cout <<"\tCorner: "<< X0 << std::endl;
for (size_t i = 0; i < nodes.size(); i += 3)
{
nodes[i] += X0.x;
nodes[i+1] += X0.y;
nodes[i+2] += X0.z;
}
}
for (size_t i = 0; i < nodes.size(); i += 3)
{
std::stringstream str;
for (size_t j = 0; j < 3; j++)
str << nodes[i+j] <<" ";
g2.append(str.str());
g2.append(rational ? "1.0\n" : "\n");
}
return g2;
}
SIMdependency::PatchVec DefaultGeometry3D::createGeometry (const SIMbase& sim) const
{
std::istringstream unitCube(this->createG2());
SIMdependency::PatchVec result;
sim.readPatches(unitCube,result,"\t");
return result;
}
TopologySet DefaultGeometry3D::createTopologySets (const SIMbase&) const
{
if (!sets)
return TopologySet();
TopologySet result;
std::string face = "Face1";
for (size_t i = 1; i <= 6; ++i, ++face.back()) {
result[face].insert(TopItem(1,i,2));
result["Boundary"].insert(TopItem(1,i,2));
}
std::string edge = "Edge1";
for (size_t i = 1; i <= 12; ++i, ++edge.back()) {
result[edge].insert(TopItem(1,i,1));
result["Frame"].insert(TopItem(1,i,1));
if (i == 9)
edge = "Edge1/"; // '/' + 1 == '0'
}
std::string vert = "Vertex1";
for (size_t i = 1; i <= 8; ++i, ++vert.back()) {
result[vert].insert(TopItem(1,i,0));
result["Corners"].insert(TopItem(1,i,0));
}
return result;
}

147
src/SIM/ModelGenerator.h Normal file
View File

@ -0,0 +1,147 @@
// $Id$
//==============================================================================
//!
//! \file ModelGenerator.h
//!
//! \date Sep 2 2016
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Base class for model generators for NURBS-based FEM simulators.
//!
//==============================================================================
#ifndef _MODEL_GENERATOR_H
#define _MODEL_GENERATOR_H
#include "SIMdependency.h"
#include "TopologySet.h"
#include <string>
class SIMbase;
class TiXmlElement;
/*!
\brief Base class for model generators for FEM simulators.
*/
class ModelGenerator
{
public:
//! \brief Constructor initializes common members
//!\ param elem XML element to parse
ModelGenerator(const TiXmlElement* elem);
//! \brief Empty destructor.
virtual ~ModelGenerator() {}
//! \brief Creates a geometry.
//! \param[in] sim SIM with patch read function to use
virtual SIMdependency::PatchVec createGeometry(const SIMbase& sim) const = 0;
//! \brief Creates topology for geometry.
//! \param[in] geo XML element containing geometry defintion
//! \param sim Simulator to apply topology to
virtual bool createTopology(SIMbase& sim) const = 0;
//! \brief Creates topology sets for geometry.
//! \param[in] sim Simulator with patch ownerships
virtual TopologySet createTopologySets(const SIMbase& sim) const = 0;
protected:
bool sets; //!< Whether to generate topologysets or not
const TiXmlElement* geo; //!< Pointer to xml element describing geometry
};
/*!
\brief Default model generator for 1D FEM simulators.
\details Generates a line.
*/
class DefaultGeometry1D : public ModelGenerator {
public:
//! \brief The constructor forwards to the base class.
//! \param[in] geo XML element containing geometry defintion
DefaultGeometry1D(const TiXmlElement* geo) : ModelGenerator(geo) {}
//! \brief Creates a 1D single-patch geometry.
//! \param[in] sim SIM with patch read function to use
SIMdependency::PatchVec createGeometry(const SIMbase& sim) const override;
//! \brief Creates the topology
//! \details No topology information for single patch models
bool createTopology(SIMbase&) const override
{ return true; }
//! \brief Creates topology sets for geometry.
TopologySet createTopologySets(const SIMbase&) const override;
protected:
//! \brief Generates the G2 description of the geometry.
//! \param nsd Number of spatial dimension
std::string createG2 (int nsd = 2) const;
};
/*!
\brief Default model generator for 2D FEM simulators.
\details Generates a rectangle.
*/
class DefaultGeometry2D : public ModelGenerator {
public:
//! \brief The constructor forwards to the base class.
//! \param[in] geo XML element containing geometry defintion
DefaultGeometry2D(const TiXmlElement* geo) : ModelGenerator(geo) {}
//! \brief Creates a 2D rectangular single-patch geometry.
//! \param[in] sim SIM with patch read function to use
SIMdependency::PatchVec createGeometry(const SIMbase& sim) const override;
//! \brief Creates the topology
//! \param sim Simulator to apply topology to
//! \details No topology information for single patch models
bool createTopology(SIMbase&) const override
{ return true; }
//! \brief Creates topology sets for geometry.
TopologySet createTopologySets(const SIMbase&) const override;
protected:
//! \brief Generates the G2 description of the geometry.
//! \param nsd Number of spatial dimension
std::string createG2 (int nsd = 3) const;
};
/*!
\brief Default model generator for 3D FEM simulators.
\details Generates a hexahedra.
*/
class DefaultGeometry3D : public ModelGenerator {
public:
//! \brief The constructor forwards to the base class.
//! \param[in] geo XML element containing geometry defintion
DefaultGeometry3D(const TiXmlElement* geo) : ModelGenerator(geo) {}
//! \brief Creates a 3D hexahedral single-patch geometry.
//! \param[in] sim Simulator with patch read function to use
SIMdependency::PatchVec createGeometry(const SIMbase& sim) const override;
//! \brief Creates the topology
//! \param sim Simulator to apply topology to
//! \details No topology information for single patch models
bool createTopology(SIMbase&) const override
{ return true; }
//! \brief Creates topology sets for geometry.
TopologySet createTopologySets(const SIMbase&) const override;
protected:
//! \brief Generates the G2 description of the geometry.
std::string createG2 (int = 3) const;
};
#endif

View File

@ -0,0 +1,468 @@
//==============================================================================
//!
//! \file TestModelGenerator.C
//!
//! \date Sep 2 2016
//!
//! \author Arne Morten Kvarving / SINTEF
//!
//! \brief Tests for default model generators.
//!
//==============================================================================
#include "IFEM.h"
#include "ModelGenerator.h"
#include "SIM1D.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 DefaultGeomTest {
std::string xml;
int dim;
std::string g2;
std::string sets;
};
class TestModelGenerator1D :
public testing::Test,
public testing::WithParamInterface<DefaultGeomTest>
{
};
class TestModelGenerator2D :
public testing::Test,
public testing::WithParamInterface<DefaultGeomTest>
{
};
class TestModelGenerator3D :
public testing::Test,
public testing::WithParamInterface<DefaultGeomTest>
{
};
auto&& DoTest = [](const DefaultGeomTest& 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(TestModelGenerator1D, Generate)
{
TiXmlDocument doc;
doc.Parse(GetParam().xml.c_str());
TestModelGeneratorWrapper<DefaultGeometry1D> gen(doc.RootElement());
std::string g2 = gen.createG2(GetParam().dim);
SIM1D sim;
TopologySet sets = gen.createTopologySets(sim);
DoTest(GetParam(), g2, sets);
}
TEST_P(TestModelGenerator2D, Generate)
{
TiXmlDocument doc;
doc.Parse(GetParam().xml.c_str());
TestModelGeneratorWrapper<DefaultGeometry2D> gen(doc.RootElement());
std::string g2 = gen.createG2(GetParam().dim);
SIM2D sim;
TopologySet sets = gen.createTopologySets(sim);
DoTest(GetParam(), g2, sets);
}
TEST_P(TestModelGenerator3D, Generate)
{
TiXmlDocument doc;
doc.Parse(GetParam().xml.c_str());
TestModelGeneratorWrapper<DefaultGeometry3D> gen(doc.RootElement());
std::string g2 = gen.createG2(GetParam().dim);
SIM3D sim;
TopologySet sets = gen.createTopologySets(sim);
DoTest(GetParam(), g2, sets);
}
const std::vector<DefaultGeomTest> geometry1D =
{{"<geometry sets=\"true\"/>", 1,
"100 1 0 0\n"
"1 0\n"
"2 2\n"
"0 0 1 1\n"
"0.0\n"
"1.0\n",
"Boundary: 1 1 0 1 2 0 \n"
"Corners: 1 1 0 1 2 0 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"},
{"<geometry/>", 3,
"100 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"0.0 0.0 0.0\n"
"1.0 0.0 0.0\n",
""},
{"<geometry X0=\"1.0 1.0 0.0\" X1=\"1.0 2.0 0.0\"/>", 3,
"100 1 0 0\n"
"3 0\n"
"2 2\n"
"0 0 1 1\n"
"1.0 1.0 0.0\n"
"1.0 2.0 0.0\n",
""},
{"<geometry L=\"2.0\"/>", 1,
"100 1 0 0\n"
"1 0\n"
"2 2\n"
"0 0 1 1\n"
"0.0\n"
"2.0\n",
""},
{"<geometry rational=\"true\" sets=\"true\"/>", 1,
"100 1 0 0\n"
"1 1\n"
"2 2\n"
"0 0 1 1\n"
"0.0 1.0\n"
"1.0 1.0\n",
"Boundary: 1 1 0 1 2 0 \n"
"Corners: 1 1 0 1 2 0 \n"
"Vertex1: 1 1 0 \n"
"Vertex2: 1 2 0 \n"}};
INSTANTIATE_TEST_CASE_P(TestModelGenerator1D, TestModelGenerator1D, testing::ValuesIn(geometry1D));
const std::vector<DefaultGeomTest> 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", ""}};
INSTANTIATE_TEST_CASE_P(TestModelGenerator2D, TestModelGenerator2D, testing::ValuesIn(geometry2D));
const std::vector<DefaultGeomTest> 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", ""}};
INSTANTIATE_TEST_CASE_P(TestModelGenerator3D, TestModelGenerator3D, testing::ValuesIn(geometry3D));