Added: Input of unstructured Lagrange mesh from xml-file

This commit is contained in:
Knut Morten Okstad 2021-06-01 17:19:26 +02:00
parent cf3261fa12
commit a73c1b5a12
10 changed files with 318 additions and 10 deletions

View File

@ -32,7 +32,9 @@ ASMbase* ASM1D::create (ASM::Discretization discretization,
return new ASMs1DC1(nd,nf);
case ASM::Lagrange:
if (nf > 10) // hack for mesh input from file
if (nf > 20) // hack for mesh input from XML-file
return new ASMu1DLag(nd,nf-20,'x');
else if (nf > 10) // hack for mesh input from Matlab file
return new ASMu1DLag(nd,nf-10,'m');
else
return new ASMs1DLag(nd,nf);

View File

@ -43,6 +43,9 @@ bool ASMu1DLag::read (std::istream& is)
case 'm':
case 'M':
return ASM::readMatlab(is,myMNPC,myCoord,nodeSets);
case 'x':
case 'X':
return ASM::readXML(is,myMNPC,myCoord,nodeSets,&elemSets);
default:
std::cerr <<" *** ASMu1DLag::read: Undefined file format."<< std::endl;
return false;

View File

@ -66,6 +66,7 @@ public:
private:
char fileType; //!< Mesh file format
std::vector<ASM::NodeSet> nodeSets; //!< Node sets for Dirichlet BCs
std::vector<ASM::NodeSet> elemSets; //!< Element sets for properties
};
#endif

View File

@ -43,6 +43,9 @@ bool ASMu2DLag::read (std::istream& is)
case 'm':
case 'M':
return ASM::readMatlab(is,myMNPC,myCoord,nodeSets);
case 'x':
case 'X':
return ASM::readXML(is,myMNPC,myCoord,nodeSets);
default:
std::cerr <<" *** ASMu2DLag::read: Undefined file format."<< std::endl;
return false;

View File

@ -12,9 +12,12 @@
//==============================================================================
#include "ASMutils.h"
#include "Utilities.h"
#include "Vec3Oper.h"
#include "Vec3.h"
#include "tinyxml.h"
#include <sstream>
#include <cstring>
#include <cctype>
@ -135,3 +138,118 @@ bool ASM::readMatlab (std::istream& is, IntMat& MNPC, std::vector<Vec3>& nodes,
return true;
}
bool ASM::readXML (std::istream& is, IntMat& MNPC, std::vector<Vec3>& nodes,
std::vector<NodeSet>& nodeSets,
std::vector<NodeSet>* elemSets)
{
char cline[128];
if (!is.getline(cline,128))
return false;
else if (!strstr(cline,"<patch>"))
{
std::cerr <<" *** ASM::readXML: Failed to read patch geometry."<< std::endl;
return false;
}
std::string data("<patch>\n");
while (is.getline(cline,128))
{
data.append(cline);
data.append("\n");
if (strstr(cline,"</patch>"))
break;
}
TiXmlDocument doc;
doc.Parse(data.c_str(),nullptr,TIXML_ENCODING_UTF8);
const TiXmlElement* tag = doc.RootElement();
if (!tag)
{
std::cerr <<" *** ASM::readXML: Malformatted XML input."<< std::endl;
return false;
}
// Lambda function for parsing nodal points from a string.
auto&& parseNodes = [&nodes](const char* data)
{
Vec3 X;
std::istringstream iss(data);
for (size_t inod = 0; iss; inod++)
{
iss >> X;
if (iss)
{
#if SP_DEBUG > 1
std::cout << inod <<": "<< X << std::endl;
#endif
nodes.push_back(X);
}
}
};
// Lambda function for parsing element connectivities from a string.
auto&& parseElements = [&MNPC](const char* data, size_t nenod)
{
IntVec mnpc(nenod);
std::istringstream iss(data);
for (size_t iel = 0; iss; iel++)
{
for (int& n : mnpc) iss >> n;
if (iss)
{
#if SP_DEBUG > 1
std::cout << iel <<":";
for (int n : mnpc) std::cout <<" "<< n;
std::cout << std::endl;
#endif
MNPC.push_back(mnpc);
}
}
};
for (tag = tag->FirstChildElement(); tag; tag = tag->NextSiblingElement())
if (tag->Value() && tag->FirstChild())
{
std::vector<ASM::NodeSet>* nset = nullptr;
if (!strcasecmp(tag->Value(),"nodes"))
parseNodes(tag->FirstChild()->Value());
else if (!strcasecmp(tag->Value(),"elements"))
{
size_t nenod = 2;
utl::getAttribute(tag,"nenod",nenod);
parseElements(tag->FirstChild()->Value(),nenod);
}
else if (!strcasecmp(tag->Value(),"nodeset"))
nset = &nodeSets;
else if (!strcasecmp(tag->Value(),"elementset"))
nset = elemSets;
if (nset)
{
int node;
IntVec nodes;
std::string name;
utl::getAttribute(tag,"name",name);
std::istringstream iss(tag->FirstChild()->Value());
iss >> node;
while (iss)
{
nodes.push_back(1+node);
iss >> node;
}
#if SP_DEBUG > 1
if (nset == &nodeSets)
std::cout <<"Node ";
else
std::cout <<"Element ";
std::cout <<"set \""<< name <<"\":";
for (int n : nodes) std::cout <<" "<< n;
std::cout << std::endl;
#endif
nset->push_back(std::make_pair(name,nodes));
}
}
return true;
}

View File

@ -31,6 +31,11 @@ namespace ASM
//! \brief Creates a mesh by reading Matlab commands from an input stream.
bool readMatlab(std::istream& is, IntMat& MNPC, std::vector<Vec3>& nodes,
std::vector<NodeSet>& nodeSets);
//! \brief Creates a mesh by reading XML tags from an input stream.
bool readXML(std::istream& is, IntMat& MNPC, std::vector<Vec3>& nodes,
std::vector<NodeSet>& nodeSets,
std::vector<NodeSet>* elemSets = nullptr);
};
#endif

52
src/ASM/Test/TestASMu1D.C Normal file
View File

@ -0,0 +1,52 @@
//==============================================================================
//!
//! \file TestASMu1D.C
//!
//! \date Jun 1 2021
//!
//! \author Knut Morten Okstad / SINTEF
//!
//! \brief Tests for unstructured 1D FE models.
//!
//==============================================================================
#include "ASMbase.h"
#include "SIM1D.h"
#include "gtest/gtest.h"
TEST(TestASMu1D, Read)
{
std::string xml("<geometry dim='3'><patchfile type='xml'>"
" src/ASM/Test/refdata/bridge.xinp"
"</patchfile></geometry>");
SIM1D sim;
ASSERT_TRUE(sim.loadXML(xml.c_str()));
ASSERT_TRUE(sim.createFEMmodel());
ASMbase* pch1 = sim.getPatch(1);
EXPECT_EQ(pch1->getNoNodes(),58u);
EXPECT_EQ(pch1->getNoElms(),40u);
Vec3 Xn = pch1->getCoord(56);
EXPECT_EQ(Xn.x,4.25);
EXPECT_EQ(Xn.y,6.25);
EXPECT_EQ(Xn.z,2.0);
Matrix Xe;
EXPECT_TRUE(pch1->getElementCoordinates(Xe,2));
EXPECT_EQ(Xe.rows(),3U);
EXPECT_EQ(Xe.cols(),2U);
EXPECT_EQ(Xe(1,1),5.0);
EXPECT_EQ(Xe(2,1),10.0);
EXPECT_EQ(Xe(3,1),0.0);
EXPECT_EQ(Xe(1,2),2.5);
EXPECT_EQ(Xe(2,2),10.0);
EXPECT_EQ(Xe(3,2),0.0);
IntVec s3 = {19,20,21,22,23};
IntVec S3 = pch1->getNodeSet(pch1->getNodeSetIdx("S03"));
EXPECT_TRUE(S3 == s3);
}

View File

@ -0,0 +1,117 @@
<patch>
<nodes>
5.0 0.0 0.0
5.0 10.0 0.0
5.0 1.25 2.0
5.0 8.75 2.0
2.5 0.0 0.0
2.5 10.0 0.0
2.5 1.25 2.0
2.5 8.75 2.0
5.0 1.75 0.0
5.0 3.25 0.0
4.25 2.5 0.0
5.0 2.102500794997615 0.635998728003816
5.0 2.897499205002385 0.635998728003816
5.0 4.25 0.0
5.0 5.75 0.0
4.25 5.0 0.0
5.0 4.602500794997615 0.635998728003816
5.0 5.397499205002385 0.635998728003816
5.0 6.75 0.0
5.0 8.25 0.0
4.25 7.5 0.0
5.0 7.102500794997615 0.635998728003816
5.0 7.897499205002385 0.635998728003816
2.5 3.25 0.0
2.5 1.75 0.0
3.25 2.5 0.0
2.5 2.897499205002385 0.635998728003816
2.5 2.102500794997615 0.635998728003816
2.5 5.75 0.0
2.5 4.25 0.0
3.25 5.0 0.0
2.5 5.397499205002385 0.635998728003816
2.5 4.602500794997615 0.635998728003816
2.5 8.25 0.0
2.5 6.75 0.0
3.25 7.5 0.0
2.5 7.897499205002385 0.635998728003816
2.5 7.102500794997615 0.635998728003816
2.5 3.0 2.0
2.5 4.5 2.0
3.25 3.75 2.0
2.5 3.352500794997615 1.364001271996184
2.5 4.147499205002385 1.364001271996184
2.5 5.5 2.0
2.5 7.0 2.0
3.25 6.25 2.0
2.5 5.852500794997615 1.364001271996184
2.5 6.647499205002385 1.364001271996184
5.0 4.5 2.0
5.0 3.0 2.0
4.25 3.75 2.0
5.0 4.147499205002385 1.364001271996184
5.0 3.352500794997615 1.364001271996184
5.0 7.0 2.0
5.0 5.5 2.0
4.25 6.25 2.0
5.0 6.647499205002385 1.364001271996184
5.0 5.852500794997615 1.364001271996184
</nodes>
<elements nenod="2">
0 4
1 5
2 6
3 7
0 2
1 3
4 6
5 7
12 52
11 2
8 0
17 57
16 51
13 9
19 1
22 3
21 56
18 14
19 1
26 41
27 6
24 4
10 25
31 46
32 42
29 23
15 30
33 5
36 7
37 47
34 28
20 35
38 6
43 39
44 7
49 2
40 50
54 48
45 55
53 3
</elements>
<nodeset name="S01"> 8 9 10 11 12</nodeset>
<nodeset name="S02">13 14 15 16 17</nodeset>
<nodeset name="S03">18 19 20 21 22</nodeset>
<nodeset name="S04">23 24 25 26 27</nodeset>
<nodeset name="S05">28 29 30 31 32</nodeset>
<nodeset name="S06">33 34 35 36 37</nodeset>
<nodeset name="S07">38 39 40 41 42</nodeset>
<nodeset name="S08">43 44 45 46 47</nodeset>
<nodeset name="S09">48 49 50 51 52</nodeset>
<nodeset name="S10">53 54 55 56 57</nodeset>
</patch>

View File

@ -264,6 +264,8 @@ bool SIM1D::parse (const TiXmlElement* elem)
{
if (type == "matlab")
nf += 10;
else if (type == "xml")
nf += 20;
else
continue;
opt.discretization = ASM::Lagrange;

View File

@ -417,23 +417,27 @@ bool SIM2D::parse (const TiXmlElement* elem)
{
if (!strcasecmp(elem->Value(),"geometry"))
{
// Check for triangular/Matlab mesh or immersed boundary calculation.
// Check for triangular/unstructured Lagrange mesh
// or immersed boundary calculation.
// This code must be placed here (and not in parseGeometryTag)
// due to instantiation of the ASMs2D[Tri|IB|Matlab] class.
int maxDepth = 0;
std::string type;
// due to instantiation of the ASMu2DLag and ASMs2D[Tri|IB] classes.
const TiXmlElement* child = elem->FirstChildElement();
for (; child; child = child->NextSiblingElement())
if (!strcasecmp(child->Value(),"triangular"))
opt.discretization = ASM::Triangle;
else if (!strcasecmp(child->Value(),"patchfile") &&
utl::getAttribute(child,"type",type,true) && type == "matlab")
else if (!strcasecmp(child->Value(),"patchfile"))
{
std::string type;
if (utl::getAttribute(child,"type",type,true) && type[0] > 'l')
{
opt.discretization = ASM::Lagrange;
nf.push_back('M');
nf.push_back(type[0]);
}
}
else if (!strcasecmp(child->Value(),"immersedboundary"))
if (utl::getAttribute(child,"max_depth",maxDepth))
{
int maxDepth = 0;
if (utl::getAttribute(child,"max_depth",maxDepth) && maxDepth > 0)
{
nf.push_back('I');
nf.push_back(maxDepth);
@ -444,6 +448,7 @@ bool SIM2D::parse (const TiXmlElement* elem)
opt.discretization = ASM::Spline;
}
}
}
bool result = this->SIMgeneric::parse(elem);