From a73c1b5a123eb30670ba8f14103eb9e05171ae29 Mon Sep 17 00:00:00 2001 From: Knut Morten Okstad Date: Tue, 1 Jun 2021 17:19:26 +0200 Subject: [PATCH] Added: Input of unstructured Lagrange mesh from xml-file --- src/ASM/ASM1D.C | 4 +- src/ASM/ASMu1DLag.C | 3 + src/ASM/ASMu1DLag.h | 1 + src/ASM/ASMu2DLag.C | 3 + src/ASM/ASMutils.C | 118 +++++++++++++++++++++++++++++++ src/ASM/ASMutils.h | 5 ++ src/ASM/Test/TestASMu1D.C | 52 ++++++++++++++ src/ASM/Test/refdata/bridge.xinp | 117 ++++++++++++++++++++++++++++++ src/SIM/SIM1D.C | 2 + src/SIM/SIM2D.C | 23 +++--- 10 files changed, 318 insertions(+), 10 deletions(-) create mode 100644 src/ASM/Test/TestASMu1D.C create mode 100644 src/ASM/Test/refdata/bridge.xinp diff --git a/src/ASM/ASM1D.C b/src/ASM/ASM1D.C index beeb4bda..cdd67a69 100644 --- a/src/ASM/ASM1D.C +++ b/src/ASM/ASM1D.C @@ -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); diff --git a/src/ASM/ASMu1DLag.C b/src/ASM/ASMu1DLag.C index b3a47568..26efb389 100644 --- a/src/ASM/ASMu1DLag.C +++ b/src/ASM/ASMu1DLag.C @@ -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; diff --git a/src/ASM/ASMu1DLag.h b/src/ASM/ASMu1DLag.h index 9e429c16..f7ad977d 100644 --- a/src/ASM/ASMu1DLag.h +++ b/src/ASM/ASMu1DLag.h @@ -66,6 +66,7 @@ public: private: char fileType; //!< Mesh file format std::vector nodeSets; //!< Node sets for Dirichlet BCs + std::vector elemSets; //!< Element sets for properties }; #endif diff --git a/src/ASM/ASMu2DLag.C b/src/ASM/ASMu2DLag.C index 36587d07..5580a821 100644 --- a/src/ASM/ASMu2DLag.C +++ b/src/ASM/ASMu2DLag.C @@ -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; diff --git a/src/ASM/ASMutils.C b/src/ASM/ASMutils.C index ff8195ab..669463aa 100644 --- a/src/ASM/ASMutils.C +++ b/src/ASM/ASMutils.C @@ -12,9 +12,12 @@ //============================================================================== #include "ASMutils.h" +#include "Utilities.h" #include "Vec3Oper.h" #include "Vec3.h" +#include "tinyxml.h" #include +#include #include @@ -135,3 +138,118 @@ bool ASM::readMatlab (std::istream& is, IntMat& MNPC, std::vector& nodes, return true; } + + +bool ASM::readXML (std::istream& is, IntMat& MNPC, std::vector& nodes, + std::vector& nodeSets, + std::vector* elemSets) +{ + char cline[128]; + if (!is.getline(cline,128)) + return false; + else if (!strstr(cline,"")) + { + std::cerr <<" *** ASM::readXML: Failed to read patch geometry."<< std::endl; + return false; + } + + std::string data("\n"); + while (is.getline(cline,128)) + { + data.append(cline); + data.append("\n"); + if (strstr(cline,"")) + 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* 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; +} diff --git a/src/ASM/ASMutils.h b/src/ASM/ASMutils.h index 615e41e9..f508b9d3 100644 --- a/src/ASM/ASMutils.h +++ b/src/ASM/ASMutils.h @@ -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& nodes, std::vector& nodeSets); + + //! \brief Creates a mesh by reading XML tags from an input stream. + bool readXML(std::istream& is, IntMat& MNPC, std::vector& nodes, + std::vector& nodeSets, + std::vector* elemSets = nullptr); }; #endif diff --git a/src/ASM/Test/TestASMu1D.C b/src/ASM/Test/TestASMu1D.C new file mode 100644 index 00000000..f4e85794 --- /dev/null +++ b/src/ASM/Test/TestASMu1D.C @@ -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("" + " src/ASM/Test/refdata/bridge.xinp" + ""); + + 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); +} diff --git a/src/ASM/Test/refdata/bridge.xinp b/src/ASM/Test/refdata/bridge.xinp new file mode 100644 index 00000000..7a3735d7 --- /dev/null +++ b/src/ASM/Test/refdata/bridge.xinp @@ -0,0 +1,117 @@ + + + 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 + + + + 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 + + + 8 9 10 11 12 + 13 14 15 16 17 + 18 19 20 21 22 + 23 24 25 26 27 + 28 29 30 31 32 + 33 34 35 36 37 + 38 39 40 41 42 + 43 44 45 46 47 + 48 49 50 51 52 + 53 54 55 56 57 + + diff --git a/src/SIM/SIM1D.C b/src/SIM/SIM1D.C index aeb889e9..84b270f2 100644 --- a/src/SIM/SIM1D.C +++ b/src/SIM/SIM1D.C @@ -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; diff --git a/src/SIM/SIM2D.C b/src/SIM/SIM2D.C index 45ec0222..bc1da1d8 100644 --- a/src/SIM/SIM2D.C +++ b/src/SIM/SIM2D.C @@ -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")) { - opt.discretization = ASM::Lagrange; - nf.push_back('M'); + std::string type; + if (utl::getAttribute(child,"type",type,true) && type[0] > 'l') + { + opt.discretization = ASM::Lagrange; + 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); @@ -443,6 +447,7 @@ bool SIM2D::parse (const TiXmlElement* elem) if (opt.discretization == ASM::SplineC1) opt.discretization = ASM::Spline; } + } } bool result = this->SIMgeneric::parse(elem);