Added: class ASMu1DLag for unstructured Lagrange 1D patches.
Changed: Moved the Matlab mesh input method to ASMutils.C file.
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "ASM1D.h"
|
||||
#include "ASMs1DC1.h"
|
||||
#include "ASMs1DLag.h"
|
||||
#include "ASMu1DLag.h"
|
||||
#include "ASMs1DSpec.h"
|
||||
#include "Vec3Oper.h"
|
||||
|
||||
@@ -32,7 +32,10 @@ ASMbase* ASM1D::create (ASM::Discretization discretization,
|
||||
return new ASMs1DC1(nd,nf);
|
||||
|
||||
case ASM::Lagrange:
|
||||
return new ASMs1DLag(nd,nf);
|
||||
if (nf > 10) // hack for mesh input from file
|
||||
return new ASMu1DLag(nd,nf-10,'m');
|
||||
else
|
||||
return new ASMs1DLag(nd,nf);
|
||||
|
||||
case ASM::Spectral:
|
||||
return new ASMs1DSpec(nd,nf);
|
||||
|
||||
@@ -146,9 +146,10 @@ protected:
|
||||
int p1; //!< Polynomial order of the basis
|
||||
|
||||
private:
|
||||
const std::vector<Vec3>& coord; //!< Nodal coordinates
|
||||
const Vec3Vec& coord; //!< Nodal coordinates
|
||||
|
||||
std::vector<Vec3> myCoord; //!< The actual nodal coordinates
|
||||
protected:
|
||||
Vec3Vec myCoord; //!< The actual nodal coordinates
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -174,9 +174,10 @@ protected:
|
||||
int p2; //!< Polynomial order in second parameter direction
|
||||
|
||||
private:
|
||||
const std::vector<Vec3>& coord; //!< Nodal coordinates
|
||||
const Vec3Vec& coord; //!< Nodal coordinates
|
||||
|
||||
std::vector<Vec3> myCoord; //!< The actual nodal coordinates
|
||||
protected:
|
||||
Vec3Vec myCoord; //!< The actual nodal coordinates
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -116,7 +116,7 @@ bool ASMsupel::generateFEMTopology ()
|
||||
int ASMsupel::getNodeSetIdx (const std::string& setName) const
|
||||
{
|
||||
int idx = 1;
|
||||
for (const NodeSet& ns : nodeSets)
|
||||
for (const ASM::NodeSet& ns : nodeSets)
|
||||
if (ns.first == setName)
|
||||
return idx;
|
||||
else
|
||||
@@ -129,7 +129,7 @@ int ASMsupel::getNodeSetIdx (const std::string& setName) const
|
||||
const IntVec& ASMsupel::getNodeSet (int idx) const
|
||||
{
|
||||
int count = 0;
|
||||
for (const NodeSet& ns : nodeSets)
|
||||
for (const ASM::NodeSet& ns : nodeSets)
|
||||
if (++count == idx)
|
||||
return ns.second;
|
||||
|
||||
@@ -139,7 +139,7 @@ const IntVec& ASMsupel::getNodeSet (int idx) const
|
||||
|
||||
IntVec& ASMsupel::getNodeSet (const std::string& setName)
|
||||
{
|
||||
for (NodeSet& ns : nodeSets)
|
||||
for (ASM::NodeSet& ns : nodeSets)
|
||||
if (ns.first == setName)
|
||||
return ns.second;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define _ASM_SUPEL_H
|
||||
|
||||
#include "ASMbase.h"
|
||||
#include "ASMutils.h"
|
||||
#include "ElmMats.h"
|
||||
#include "Vec3.h"
|
||||
|
||||
@@ -112,8 +113,7 @@ private:
|
||||
Vec3Vec myNodes; //!< Supernode coordinates
|
||||
ElmMats myElmMat; //!< Duperelement matrices
|
||||
|
||||
typedef std::pair<std::string,IntVec> NodeSet; //!< Named node set container
|
||||
std::vector<NodeSet> nodeSets; //!< Pre-defined node sets for Dirichlet BCs
|
||||
std::vector<ASM::NodeSet> nodeSets; //!< Node sets for Dirichlet BCs
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
129
src/ASM/ASMu1DLag.C
Normal file
129
src/ASM/ASMu1DLag.C
Normal file
@@ -0,0 +1,129 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file ASMu1DLag.C
|
||||
//!
|
||||
//! \date Aug 26 2021
|
||||
//!
|
||||
//! \author Knut Morten Okstad / SINTEF
|
||||
//!
|
||||
//! \brief Assembly of unstructured 1D Lagrange FE models.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "ASMu1DLag.h"
|
||||
#include "ElementBlock.h"
|
||||
#include <numeric>
|
||||
|
||||
|
||||
ASMu1DLag::ASMu1DLag (unsigned char n_s,
|
||||
unsigned char n_f, char fType) : ASMs1DLag(n_s,n_f)
|
||||
{
|
||||
fileType = fType;
|
||||
}
|
||||
|
||||
|
||||
ASMu1DLag::ASMu1DLag (const ASMu1DLag& p, unsigned char n_f) :
|
||||
ASMs1DLag(p,n_f), nodeSets(p.nodeSets)
|
||||
{
|
||||
fileType = 0;
|
||||
}
|
||||
|
||||
|
||||
ASMu1DLag::ASMu1DLag (const ASMu1DLag& p) :
|
||||
ASMs1DLag(p), nodeSets(p.nodeSets)
|
||||
{
|
||||
fileType = 0;
|
||||
}
|
||||
|
||||
|
||||
bool ASMu1DLag::read (std::istream& is)
|
||||
{
|
||||
switch (fileType) {
|
||||
case 'm':
|
||||
case 'M':
|
||||
return ASM::readMatlab(is,myMNPC,myCoord,nodeSets);
|
||||
default:
|
||||
std::cerr <<" *** ASMu1DLag::read: Undefined file format."<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ASMu1DLag::generateOrientedFEModel (const Vec3& Zaxis)
|
||||
{
|
||||
p1 = 2; // So far only linear elements supported
|
||||
|
||||
nnod = myCoord.size();
|
||||
nel = myMNPC.size();
|
||||
|
||||
myMLGN.resize(nnod);
|
||||
myMLGE.resize(nel);
|
||||
if (nsd == 3 && nf == 6)
|
||||
{
|
||||
// This is a 3D beam problem, allocate the nodal/element rotation tensors.
|
||||
// The nodal rotations are updated during the simulation according to the
|
||||
// deformation state, whereas the element tensors are kept constant.
|
||||
myCS.resize(nel,Tensor(3));
|
||||
myT.resize(nnod,Tensor(3,true)); // Initialize nodal rotations to unity
|
||||
}
|
||||
|
||||
std::iota(myMLGN.begin(),myMLGN.end(),gNod+1);
|
||||
std::iota(myMLGE.begin(),myMLGE.end(),gEl+1);
|
||||
|
||||
gNod += nnod;
|
||||
gEl += nel;
|
||||
|
||||
return myCS.empty() ? true : this->initLocalElementAxes(Zaxis);
|
||||
}
|
||||
|
||||
|
||||
int ASMu1DLag::getNodeSetIdx (const std::string& setName) const
|
||||
{
|
||||
int idx = 1;
|
||||
for (const ASM::NodeSet& ns : nodeSets)
|
||||
if (ns.first == setName)
|
||||
return idx;
|
||||
else
|
||||
++idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const IntVec& ASMu1DLag::getNodeSet (int idx) const
|
||||
{
|
||||
int count = 0;
|
||||
for (const ASM::NodeSet& ns : nodeSets)
|
||||
if (++count == idx)
|
||||
return ns.second;
|
||||
|
||||
return this->ASMbase::getNodeSet(idx);
|
||||
}
|
||||
|
||||
|
||||
IntVec& ASMu1DLag::getNodeSet (const std::string& setName)
|
||||
{
|
||||
for (ASM::NodeSet& ns : nodeSets)
|
||||
if (ns.first == setName)
|
||||
return ns.second;
|
||||
|
||||
nodeSets.push_back(std::make_pair(setName,IntVec()));
|
||||
return nodeSets.back().second;
|
||||
}
|
||||
|
||||
|
||||
bool ASMu1DLag::tesselate (ElementBlock& grid, const int*) const
|
||||
{
|
||||
grid.unStructResize(nel,nnod);
|
||||
|
||||
size_t i, k;
|
||||
for (i = 0; i < nnod; i++)
|
||||
grid.setCoor(i,this->getCoord(1+i));
|
||||
|
||||
for (i = k = 0; i < nel; i++)
|
||||
for (int j : MNPC[i])
|
||||
grid.setNode(k++,j);
|
||||
|
||||
return true;
|
||||
}
|
||||
71
src/ASM/ASMu1DLag.h
Normal file
71
src/ASM/ASMu1DLag.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file ASMu1DLag.h
|
||||
//!
|
||||
//! \date May 26 2021
|
||||
//!
|
||||
//! \author Knut Morten Okstad / SINTEF
|
||||
//!
|
||||
//! \brief Assembly of unstructured 1D Lagrange FE models.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _ASM_U1D_LAG_H
|
||||
#define _ASM_U1D_LAG_H
|
||||
|
||||
#include "ASMs1DLag.h"
|
||||
#include "ASMutils.h"
|
||||
|
||||
|
||||
/*!
|
||||
\brief Driver for assembly of unstructured 1D Lagrange FE models.
|
||||
\details This class overrides the methods of its parent class such that
|
||||
it does not depend on a curve spline object for geometry discretization.
|
||||
It can therefore be used for any unstructured grid read from mesh files.
|
||||
*/
|
||||
|
||||
class ASMu1DLag : public ASMs1DLag
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
ASMu1DLag(unsigned char n = 1, unsigned char n_f = 1, char fType = 'm');
|
||||
//! \brief Special copy constructor for sharing of FE data.
|
||||
ASMu1DLag(const ASMu1DLag& pch, unsigned char n_f);
|
||||
//! \brief Default copy constructor copying everything.
|
||||
ASMu1DLag(const ASMu1DLag& pch);
|
||||
//! \brief Empty destructor.
|
||||
virtual ~ASMu1DLag() {}
|
||||
|
||||
// Methods for model generation
|
||||
// ============================
|
||||
|
||||
//! \brief Creates an instance by reading the given input stream.
|
||||
virtual bool read(std::istream& is);
|
||||
//! \brief Generates a beam finite element model for the patch.
|
||||
//! \param[in] Zaxis Vector defining a point in the local XZ-plane
|
||||
virtual bool generateOrientedFEModel(const Vec3& Zaxis);
|
||||
//! \brief Checks if this patch is empty.
|
||||
virtual bool empty() const { return nel == 0; }
|
||||
|
||||
//! \brief Returns (1-based) index of a predefined node set in the patch.
|
||||
virtual int getNodeSetIdx(const std::string& setName) const;
|
||||
//! \brief Returns an indexed pre-defined node set.
|
||||
virtual const IntVec& getNodeSet(int idx) const;
|
||||
//! \brief Returns a named node set for update.
|
||||
virtual IntVec& getNodeSet(const std::string& setName);
|
||||
|
||||
// Post-processing methods
|
||||
// =======================
|
||||
|
||||
//! \brief Creates a line element model of this patch for visualization.
|
||||
//! \param[out] grid The generated line grid
|
||||
//! \note The number of element nodes must be set in \a grid on input.
|
||||
virtual bool tesselate(ElementBlock& grid, const int*) const;
|
||||
|
||||
private:
|
||||
char fileType; //!< Mesh file format
|
||||
std::vector<ASM::NodeSet> nodeSets; //!< Node sets for Dirichlet BCs
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -13,10 +13,7 @@
|
||||
|
||||
#include "ASMu2DLag.h"
|
||||
#include "ElementBlock.h"
|
||||
#include "Vec3Oper.h"
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
|
||||
ASMu2DLag::ASMu2DLag (unsigned char n_s,
|
||||
@@ -40,136 +37,12 @@ ASMu2DLag::ASMu2DLag (const ASMu2DLag& p) :
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Helper method reading one data line ignoring all whitespace characters.
|
||||
\param is Input stream to read data from
|
||||
\param[out] s The read data is placed in this string
|
||||
\param[in] delim Read until this character is reached
|
||||
*/
|
||||
|
||||
static bool readLine (std::istream& is, std::string& s, char delim = '\n')
|
||||
{
|
||||
size_t i, n = 0;
|
||||
while (n == 0 && std::getline(is,s,delim))
|
||||
for (i = 0; i < s.length(); i++)
|
||||
if (!isspace(s[i])) s[n++] = s[i];
|
||||
|
||||
s = s.substr(0,n);
|
||||
for (i = 0; i < n; i++)
|
||||
if (s[i] == ',') s[i] = ' ';
|
||||
|
||||
return n > 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
This method reads a matlab file with arrays defining a standard FE mesh.
|
||||
The format corresponds to that of the output method SIMoutput::dumpMatlabGrid.
|
||||
*/
|
||||
|
||||
bool ASMu2DLag::readMatlab (std::istream& is)
|
||||
{
|
||||
std::string cline;
|
||||
if (!readLine(is,cline,'=') ||
|
||||
cline.find("function") == std::string::npos ||
|
||||
cline.find("Node") == std::string::npos ||
|
||||
cline.find("Element") == std::string::npos)
|
||||
{
|
||||
std::cerr <<" *** ASMu2DLag::readMatlab: Not a matlab file."<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::getline(is,cline);
|
||||
while (readLine(is,cline,'['))
|
||||
if (cline.find("Node=") == cline.length()-5)
|
||||
{
|
||||
while (readLine(is,cline))
|
||||
{
|
||||
size_t id; Vec3 X;
|
||||
std::stringstream(cline) >> id >> X;
|
||||
#if SP_DEBUG > 1
|
||||
std::cout << id <<": "<< X << std::endl;
|
||||
#endif
|
||||
this->setCoord(id,X);
|
||||
if (cline.back() == ';') break;
|
||||
}
|
||||
#ifdef SP_DEBUG
|
||||
std::cout <<"Read "<< nnod <<" nodes."<< std::endl;
|
||||
#endif
|
||||
}
|
||||
else if (cline.find("Element=") == cline.length()-8)
|
||||
{
|
||||
while (readLine(is,cline))
|
||||
{
|
||||
size_t id; int node;
|
||||
IntVec mnpc; mnpc.reserve(4);
|
||||
std::istringstream selem(cline);
|
||||
selem >> id >> node;
|
||||
while (selem)
|
||||
{
|
||||
mnpc.push_back(node-1);
|
||||
selem >> node;
|
||||
}
|
||||
#if SP_DEBUG > 1
|
||||
std::cout << id <<":";
|
||||
for (int n : mnpc) std::cout <<" "<< n;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
if (mnpc.size() == 4)
|
||||
std::swap(mnpc[2],mnpc[3]);
|
||||
else
|
||||
{
|
||||
std::cerr <<" ** ASMu2DLag::readMatlab: "<< mnpc.size()
|
||||
<<"-noded elements not supported (ignored).\n";
|
||||
continue;
|
||||
}
|
||||
if (id > myMNPC.size()) myMNPC.resize(id);
|
||||
myMNPC[id-1] = mnpc;
|
||||
if (cline.back() == ';') break;
|
||||
}
|
||||
nel = myMNPC.size();
|
||||
#ifdef SP_DEBUG
|
||||
std::cout <<"Read "<< nel <<" elements."<< std::endl;
|
||||
#endif
|
||||
}
|
||||
else if (cline.back() == '=')
|
||||
{
|
||||
std::string setname = cline.substr(0,cline.length()-1);
|
||||
if (readLine(is,cline,']'))
|
||||
{
|
||||
size_t i = 0; // Remove the '...' continuation markers
|
||||
while ((i = cline.find_first_of('.',i)) != std::string::npos)
|
||||
cline.erase(i,1);
|
||||
|
||||
int node;
|
||||
IntVec nodes;
|
||||
std::istringstream selem(cline);
|
||||
selem >> node;
|
||||
while (selem)
|
||||
{
|
||||
nodes.push_back(node);
|
||||
selem >> node;
|
||||
}
|
||||
#if SP_DEBUG > 1
|
||||
std::cout <<"Node set \""<< setname <<"\":";
|
||||
for (int n : nodes) std::cout <<" "<< n;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
std::getline(is,cline);
|
||||
nodeSets.push_back(std::make_pair(setname,nodes));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ASMu2DLag::read (std::istream& is)
|
||||
{
|
||||
switch (fileType) {
|
||||
case 'm':
|
||||
case 'M':
|
||||
return this->readMatlab(is);
|
||||
return ASM::readMatlab(is,myMNPC,myCoord,nodeSets);
|
||||
default:
|
||||
std::cerr <<" *** ASMu2DLag::read: Undefined file format."<< std::endl;
|
||||
return false;
|
||||
@@ -181,6 +54,9 @@ bool ASMu2DLag::generateFEMTopology ()
|
||||
{
|
||||
p1 = p2 = 2; // So far only linear elements supported
|
||||
|
||||
nnod = myCoord.size();
|
||||
nel = myMNPC.size();
|
||||
|
||||
myMLGN.resize(nnod);
|
||||
myMLGE.resize(nel);
|
||||
|
||||
@@ -197,8 +73,8 @@ bool ASMu2DLag::generateFEMTopology ()
|
||||
int ASMu2DLag::getNodeSetIdx (const std::string& setName) const
|
||||
{
|
||||
int idx = 1;
|
||||
for (const auto& it : nodeSets)
|
||||
if (it.first == setName)
|
||||
for (const ASM::NodeSet& ns : nodeSets)
|
||||
if (ns.first == setName)
|
||||
return idx;
|
||||
else
|
||||
++idx;
|
||||
@@ -210,9 +86,9 @@ int ASMu2DLag::getNodeSetIdx (const std::string& setName) const
|
||||
const IntVec& ASMu2DLag::getNodeSet (int idx) const
|
||||
{
|
||||
int count = 0;
|
||||
for (const auto& it : nodeSets)
|
||||
for (const ASM::NodeSet& ns : nodeSets)
|
||||
if (++count == idx)
|
||||
return it.second;
|
||||
return ns.second;
|
||||
|
||||
return this->ASMbase::getNodeSet(idx);
|
||||
}
|
||||
@@ -220,9 +96,9 @@ const IntVec& ASMu2DLag::getNodeSet (int idx) const
|
||||
|
||||
IntVec& ASMu2DLag::getNodeSet (const std::string& setName)
|
||||
{
|
||||
for (NodeSet& it : nodeSets)
|
||||
if (it.first == setName)
|
||||
return it.second;
|
||||
for (ASM::NodeSet& ns : nodeSets)
|
||||
if (ns.first == setName)
|
||||
return ns.second;
|
||||
|
||||
nodeSets.push_back(std::make_pair(setName,IntVec()));
|
||||
return nodeSets.back().second;
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _ASM_S2D_MATLAB_H
|
||||
#define _ASM_S2D_MATLAB_H
|
||||
#ifndef _ASM_U2D_LAG_H
|
||||
#define _ASM_U2D_LAG_H
|
||||
|
||||
#include "ASMs2DLag.h"
|
||||
#include "ASMutils.h"
|
||||
|
||||
|
||||
/*!
|
||||
@@ -30,7 +31,7 @@ public:
|
||||
//! \brief Default constructor.
|
||||
ASMu2DLag(unsigned char n = 2, unsigned char n_f = 2, char fType = 'm');
|
||||
//! \brief Special copy constructor for sharing of FE data.
|
||||
ASMu2DLag(const ASMu2DLag& pch, unsigned char nf);
|
||||
ASMu2DLag(const ASMu2DLag& pch, unsigned char n_f);
|
||||
//! \brief Default copy constructor copying everything.
|
||||
ASMu2DLag(const ASMu2DLag& pch);
|
||||
//! \brief Empty destructor.
|
||||
@@ -39,11 +40,6 @@ public:
|
||||
// Methods for model generation
|
||||
// ============================
|
||||
|
||||
private:
|
||||
//! \brief Creates an instance by reading Matlab commands from a stream.
|
||||
bool readMatlab(std::istream& is);
|
||||
|
||||
public:
|
||||
//! \brief Creates an instance by reading the given input stream.
|
||||
virtual bool read(std::istream& is);
|
||||
//! \brief Generates the finite element topology data for the patch.
|
||||
@@ -71,9 +67,8 @@ public:
|
||||
virtual bool tesselate(ElementBlock& grid, const int*) const;
|
||||
|
||||
private:
|
||||
char fileType; //!< Mesh file format
|
||||
typedef std::pair<std::string,IntVec> NodeSet; //!< Named node set container
|
||||
std::vector<NodeSet> nodeSets; //!< Pre-defined node sets for Dirichlet BCs
|
||||
char fileType; //!< Mesh file format
|
||||
std::vector<ASM::NodeSet> nodeSets; //!< Node sets for Dirichlet BCs
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
137
src/ASM/ASMutils.C
Normal file
137
src/ASM/ASMutils.C
Normal file
@@ -0,0 +1,137 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file ASMutils.C
|
||||
//!
|
||||
//! \date Aug 12 2017
|
||||
//!
|
||||
//! \author Knut Morten Okstad / SINTEF
|
||||
//!
|
||||
//! \brief Various utilities for assembly scope.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "ASMutils.h"
|
||||
#include "Vec3Oper.h"
|
||||
#include "Vec3.h"
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
|
||||
/*!
|
||||
This function reads a matlab file with arrays defining a standard FE mesh.
|
||||
The format corresponds to that of the output method SIMoutput::dumpMatlabGrid.
|
||||
*/
|
||||
|
||||
bool ASM::readMatlab (std::istream& is, IntMat& MNPC, std::vector<Vec3>& nodes,
|
||||
std::vector<NodeSet>& nodeSets)
|
||||
{
|
||||
// Lambda function reading one data line ignoring all whitespace characters.
|
||||
auto&& readLine = [&is](std::string& s, char delim = '\n')
|
||||
{
|
||||
size_t i, n = 0;
|
||||
while (n == 0 && std::getline(is,s,delim))
|
||||
for (i = 0; i < s.length(); i++)
|
||||
if (!isspace(s[i])) s[n++] = s[i];
|
||||
|
||||
s = s.substr(0,n);
|
||||
for (i = 0; i < n; i++)
|
||||
if (s[i] == ',') s[i] = ' ';
|
||||
|
||||
return n > 0;
|
||||
};
|
||||
|
||||
std::string cline;
|
||||
if (!readLine(cline,'=') ||
|
||||
cline.find("function") == std::string::npos ||
|
||||
cline.find("Node") == std::string::npos ||
|
||||
cline.find("Element") == std::string::npos)
|
||||
{
|
||||
std::cerr <<" *** ASM::readMatlab: Not a matlab file."<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::getline(is,cline);
|
||||
while (readLine(cline,'['))
|
||||
if (cline.find("Node=") == cline.length()-5)
|
||||
{
|
||||
while (readLine(cline))
|
||||
{
|
||||
size_t id; Vec3 X;
|
||||
std::istringstream(cline) >> id >> X;
|
||||
#if SP_DEBUG > 1
|
||||
std::cout << id <<": "<< X << std::endl;
|
||||
#endif
|
||||
if (id > nodes.size()) nodes.resize(id);
|
||||
nodes[id-1] = X;
|
||||
|
||||
if (cline.back() == ';') break;
|
||||
}
|
||||
#ifdef SP_DEBUG
|
||||
std::cout <<"Read "<< nodes.size() <<" nodes."<< std::endl;
|
||||
#endif
|
||||
}
|
||||
else if (cline.find("Element=") == cline.length()-8)
|
||||
{
|
||||
while (readLine(cline))
|
||||
{
|
||||
size_t id; int node;
|
||||
IntVec mnpc; mnpc.reserve(4);
|
||||
std::istringstream selem(cline);
|
||||
selem >> id >> node;
|
||||
while (selem)
|
||||
{
|
||||
mnpc.push_back(node-1);
|
||||
selem >> node;
|
||||
}
|
||||
#if SP_DEBUG > 1
|
||||
std::cout << id <<":";
|
||||
for (int n : mnpc) std::cout <<" "<< n;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
if (mnpc.size() == 4)
|
||||
std::swap(mnpc[2],mnpc[3]);
|
||||
else if (mnpc.size() != 2)
|
||||
{
|
||||
std::cerr <<" ** ASM::readMatlab: "<< mnpc.size()
|
||||
<<"-noded elements not supported (ignored).\n";
|
||||
continue;
|
||||
}
|
||||
if (id > MNPC.size()) MNPC.resize(id);
|
||||
MNPC[id-1] = mnpc;
|
||||
if (cline.back() == ';') break;
|
||||
}
|
||||
#ifdef SP_DEBUG
|
||||
std::cout <<"Read "<< MNPC.size() <<" elements."<< std::endl;
|
||||
#endif
|
||||
}
|
||||
else if (cline.back() == '=')
|
||||
{
|
||||
std::string setname = cline.substr(0,cline.length()-1);
|
||||
if (readLine(cline,']'))
|
||||
{
|
||||
size_t i = 0; // Remove the '...' continuation markers
|
||||
while ((i = cline.find_first_of('.',i)) != std::string::npos)
|
||||
cline.erase(i,1);
|
||||
|
||||
int node;
|
||||
IntVec nodes;
|
||||
std::istringstream selem(cline);
|
||||
selem >> node;
|
||||
while (selem)
|
||||
{
|
||||
nodes.push_back(node);
|
||||
selem >> node;
|
||||
}
|
||||
#if SP_DEBUG > 1
|
||||
std::cout <<"Node set \""<< setname <<"\":";
|
||||
for (int n : nodes) std::cout <<" "<< n;
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
std::getline(is,cline);
|
||||
nodeSets.push_back(std::make_pair(setname,nodes));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
36
src/ASM/ASMutils.h
Normal file
36
src/ASM/ASMutils.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// $Id$
|
||||
//==============================================================================
|
||||
//!
|
||||
//! \file ASMutils.h
|
||||
//!
|
||||
//! \date Aug 12 2017
|
||||
//!
|
||||
//! \author Knut Morten Okstad / SINTEF
|
||||
//!
|
||||
//! \brief Various utilities for assembly scope.
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _ASM_UTILS_H
|
||||
#define _ASM_UTILS_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class Vec3;
|
||||
|
||||
typedef std::vector<int> IntVec; //!< General integer vector
|
||||
typedef std::vector<IntVec> IntMat; //!< General 2D integer matrix
|
||||
|
||||
|
||||
namespace ASM
|
||||
{
|
||||
typedef std::pair<std::string,IntVec> NodeSet; //!< Named node set container
|
||||
|
||||
//! \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);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,9 @@
|
||||
//!
|
||||
//==============================================================================
|
||||
|
||||
#include "SIM1D.h"
|
||||
#include "SIM2D.h"
|
||||
#include "ASMs1D.h"
|
||||
#include "ASMs2D.h"
|
||||
#include "ModelGenerator.h"
|
||||
#include "tinyxml.h"
|
||||
@@ -19,6 +21,27 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
|
||||
class SIM1D_default : public SIM1D
|
||||
{
|
||||
public:
|
||||
SIM1D_default(int nu)
|
||||
{
|
||||
// Create a unit grid with (nu+1) linear elements
|
||||
this->createDefaultModel();
|
||||
ASMs1D* pch1 = static_cast<ASMs1D*>(myModel.front());
|
||||
EXPECT_TRUE(pch1->uniformRefine(nu));
|
||||
EXPECT_TRUE(this->createFEMmodel());
|
||||
|
||||
// Create topological boundary entities (vertices)
|
||||
TiXmlDocument doc;
|
||||
doc.Parse("<geometry sets='true'/>",nullptr,TIXML_ENCODING_UTF8);
|
||||
DefaultGeometry1D(doc.RootElement()).createTopologySets(*this);
|
||||
EXPECT_EQ(myEntitys.size(),4U);
|
||||
}
|
||||
virtual ~SIM1D_default() {}
|
||||
};
|
||||
|
||||
|
||||
class SIM2D_default : public SIM2D
|
||||
{
|
||||
public:
|
||||
@@ -41,6 +64,23 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class SIM1D_matlab : public SIM1D
|
||||
{
|
||||
public:
|
||||
SIM1D_matlab(const char* inputFile)
|
||||
{
|
||||
std::string xml("<geometry><patchfile type='matlab'>");
|
||||
xml.append(inputFile);
|
||||
xml.append("</patchfile></geometry>");
|
||||
|
||||
// Read the FE model from the provided Matlab file
|
||||
EXPECT_TRUE(this->loadXML(xml.c_str()));
|
||||
EXPECT_TRUE(this->createFEMmodel());
|
||||
}
|
||||
virtual ~SIM1D_matlab() {}
|
||||
};
|
||||
|
||||
|
||||
class SIM2D_matlab : public SIM2D
|
||||
{
|
||||
public:
|
||||
@@ -48,7 +88,7 @@ public:
|
||||
{
|
||||
std::string xml("<geometry><patchfile type='matlab'>");
|
||||
xml.append(inputFile);
|
||||
xml.append("</geometry>");
|
||||
xml.append("</patchfile></geometry>");
|
||||
|
||||
// Read the FE model from the provided Matlab file
|
||||
EXPECT_TRUE(this->loadXML(xml.c_str()));
|
||||
@@ -62,12 +102,12 @@ TEST(TestMatlabPatch, IO)
|
||||
{
|
||||
// Create a 5x4 element mesh and write it to a matlab file
|
||||
SIM2D_default sim1(4,3);
|
||||
std::ofstream out("/tmp/testGrid.m");
|
||||
std::ofstream out("/tmp/testGrid2.m");
|
||||
ASSERT_TRUE(sim1.dumpMatlabGrid(out,"TheMesh",{"Boundary","Edge2"}));
|
||||
out.close();
|
||||
|
||||
// Read the matlab file into a new SIM and compare the models
|
||||
SIM2D_matlab sim2("/tmp/testGrid.m");
|
||||
SIM2D_matlab sim2("/tmp/testGrid2.m");
|
||||
EXPECT_EQ(sim1.getNoNodes(),sim2.getNoNodes());
|
||||
EXPECT_EQ(sim1.getNoElms(),sim2.getNoElms());
|
||||
ASMbase* pch1 = sim1.getPatch(1);
|
||||
@@ -96,4 +136,36 @@ TEST(TestMatlabPatch, IO)
|
||||
IntVec corner = pch2->getNodeSet(idx3);
|
||||
ASSERT_EQ(corner.size(),1U);
|
||||
EXPECT_EQ(corner.front(),1);
|
||||
|
||||
// Create a 6-element 1D mesh and write it to a matlab file
|
||||
SIM1D_default sim3(5);
|
||||
out.open("/tmp/testGrid1.m");
|
||||
ASSERT_TRUE(sim3.dumpMatlabGrid(out,"TheMesh",{"Boundary","Vertex2"}));
|
||||
out.close();
|
||||
|
||||
// Read the matlab file into a new SIM and compare the models
|
||||
SIM1D_matlab sim4("/tmp/testGrid1.m");
|
||||
EXPECT_EQ(sim3.getNoNodes(),sim3.getNoNodes());
|
||||
EXPECT_EQ(sim3.getNoElms(),sim3.getNoElms());
|
||||
pch1 = sim3.getPatch(1);
|
||||
pch2 = sim4.getPatch(1);
|
||||
ASSERT_TRUE(pch1 != nullptr);
|
||||
ASSERT_TRUE(pch2 != nullptr);
|
||||
idx1 = pch2->getNodeSetIdx("Boundary");
|
||||
idx2 = pch2->getNodeSetIdx("Vertex2");
|
||||
EXPECT_EQ(idx1,1);
|
||||
EXPECT_EQ(idx2,2);
|
||||
|
||||
b1.clear();
|
||||
b2 = pch2->getNodeSet(idx1);
|
||||
for (int vert = 1; vert <= 2; vert++)
|
||||
pch1->getBoundaryNodes(vert,b1);
|
||||
b1set.clear();
|
||||
for (int n : b1) b1set.insert(n);
|
||||
EXPECT_EQ(b1set.size(),b2.size());
|
||||
EXPECT_TRUE(IntVec(b1set.begin(),b1set.end()) == b2);
|
||||
IntVec v1, v2 = pch2->getNodeSet(idx2);
|
||||
pch1->getBoundaryNodes(2,v1);
|
||||
EXPECT_EQ(v1.size(),v2.size());
|
||||
EXPECT_TRUE(v1 == v2);
|
||||
}
|
||||
|
||||
@@ -250,11 +250,31 @@ bool SIM1D::parseBCTag (const TiXmlElement* elem)
|
||||
|
||||
bool SIM1D::parse (const TiXmlElement* elem)
|
||||
{
|
||||
// Check if the number of dimensions is specified
|
||||
int idim = nsd;
|
||||
if (!strcasecmp(elem->Value(),"geometry"))
|
||||
{
|
||||
// Check for unstructured Lagrange mesh.
|
||||
// This code must be placed here (and not in parseGeometryTag)
|
||||
// due to instantiation of the ASMu1DLag class.
|
||||
const TiXmlElement* child = elem->FirstChildElement();
|
||||
for (; child && nf < 10; child = child->NextSiblingElement())
|
||||
if (!strcasecmp(child->Value(),"patchfile"))
|
||||
{
|
||||
std::string type;
|
||||
if (utl::getAttribute(child,"type",type,true))
|
||||
{
|
||||
if (type == "matlab")
|
||||
nf += 10;
|
||||
else
|
||||
continue;
|
||||
opt.discretization = ASM::Lagrange;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the number of dimensions is specified
|
||||
int idim = nsd;
|
||||
if (utl::getAttribute(elem,"dim",idim))
|
||||
nsd = idim;
|
||||
}
|
||||
|
||||
bool result = this->SIMgeneric::parse(elem);
|
||||
|
||||
|
||||
@@ -1316,12 +1316,6 @@ bool SIMoutput::dumpMatlabGrid (std::ostream& os, const std::string& name,
|
||||
const std::vector<std::string>& sets,
|
||||
double scale) const
|
||||
{
|
||||
if (this->getNoParamDim() != 2)
|
||||
{
|
||||
std::cerr <<" *** SIMoutput::dumpMatlabGrid: For 2D only."<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write function definition
|
||||
os <<"function [Node, Element";
|
||||
for (const std::string& setname : sets) os <<", "<< setname;
|
||||
|
||||
Reference in New Issue
Block a user