ABAQUSsurfaceFormat.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2020-2024 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ABAQUSsurfaceFormat.H"
29 #include "ListOps.H"
30 #include "IFstream.H"
31 #include "IOmanip.H"
32 #include "faceTraits.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 template<class Face>
38 (
39  Ostream& os,
40  const Face& f,
41  label elemId,
42  const std::string& elsetName,
43  bool header
44 )
45 {
46  const label n = f.size();
47 
48  if (n == 4)
49  {
50  if (header)
51  {
52  os << "*ELEMENT, TYPE=S4";
53 
54  if (!elsetName.empty())
55  {
56  os << ", ELSET=" << elsetName;
57  }
58  os << nl;
59  }
60 
61  os << " "
62  << (++elemId) << ','
63  << (f[0] + 1) << ','
64  << (f[1] + 1) << ','
65  << (f[2] + 1) << ','
66  << (f[3] + 1) << nl;
67  }
68  else
69  {
70  if (header)
71  {
72  os << "*ELEMENT, TYPE=S3";
73 
74  if (!elsetName.empty())
75  {
76  os << ", ELSET=" << elsetName;
77  }
78  os << nl;
79  }
80 
81  if (n == 3)
82  {
83  os << " "
84  << (++elemId) << ','
85  << (f[0] + 1) << ','
86  << (f[1] + 1) << ','
87  << (f[2] + 1) << nl;
88  }
89  else
90  {
91  // simple triangulation about f[0].
92  // better triangulation should have been done before
93 
94  for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
95  {
96  const label fp2 = f.fcIndex(fp1);
97 
98  os << " "
99  << (++elemId) << ','
100  << (f[0] + 1) << ','
101  << (f[fp1] + 1) << ','
102  << (f[fp2] + 1) << nl;
103  }
104  }
105  }
106 
107  return elemId;
108 }
109 
110 
111 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
112 
113 template<class Face>
115 (
116  const fileName& filename
117 )
118 {
119  read(filename);
120 }
121 
122 
123 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
124 
125 template<class Face>
127 (
128  const fileName& filename
129 )
130 {
131  // Clear everything
132  this->clear();
133 
134  IFstream is(filename);
135  if (!is.good())
136  {
138  << "Cannot read file " << filename << nl
139  << exit(FatalError);
140  }
141 
142 
143  #ifdef FULLDEBUG
144  ABAQUSCore::readHelper reader(true); // Debugging verbosity
145  #else
146  ABAQUSCore::readHelper reader;
147  #endif
148 
149 
150  reader.read(is);
151 
152  // This needs more work
153 
154  // No solids
155  reader.purge_solids();
156  reader.compact_nodes();
157  reader.renumber_elements_1to0(); // Convert 1-based -> 0-based
158 
159 
160  // Convert connectivity to faces
161 
162  DynamicList<Face> dynFaces(reader.connectivity_.size());
163 
164  for (labelList& conn : reader.connectivity_)
165  {
166  dynFaces.append(Face(std::move(conn)));
167  }
168 
169 
170  // Rationalize the zones (elset)
171 
172  // Only retain element sets that are actually used
173  labelHashSet elsetUsed(reader.elsetIds_);
174 
175  labelList newToOldZone(elsetUsed.sortedToc());
176 
177  // Extra safety
178  if (newToOldZone.empty())
179  {
180  newToOldZone.push_back(0);
181  }
182 
183  wordList zoneNames(newToOldZone.size());
184  labelList zoneSizes(newToOldZone.size(), Foam::zero{});
185 
186  Map<label> oldToNewZone(invertToMap(newToOldZone));
187 
188  forAllConstIters(reader.elsetMap_, iter)
189  {
190  const label zonei = oldToNewZone.lookup(iter.val(), -1);
191 
192  if (zonei >= 0)
193  {
194  zoneNames[zonei] = word::validate(iter.key());
195  }
196  }
197 
198  // No empty strings
199  forAll(zoneNames, zonei)
200  {
201  if (zoneNames[zonei].empty())
202  {
203  zoneNames[zonei] = surfZoneIdentifier::defaultName(zonei);
204  }
205  }
206 
207  // Steal the elset Ids for our zones
208  DynamicList<label> dynZones(std::move(reader.elsetIds_));
209 
210  // Renumber elset -> zoneId and increment the count
211  for (label& zonei : dynZones)
212  {
213  zonei = oldToNewZone.lookup(zonei, 0);
214 
215  ++zoneSizes[zonei];
216  }
217 
218 
219  // Transfer to normal lists
220  this->storedPoints().transfer(reader.points_);
221 
222  this->sortFacesAndStore
223  (
224  dynFaces,
225  dynZones,
226  reader.elemIds_,
227  true // sorted
228  );
229 
230  // Add zones (retaining empty ones)
231  this->addZones(zoneSizes, zoneNames);
232  this->addZonesToFaces(); // for labelledTri
234  return true;
235 }
236 
237 
238 template<class Face>
240 (
241  const fileName& filename,
242  const MeshedSurfaceProxy<Face>& surf,
243  IOstreamOption streamOpt,
244  const dictionary&
245 )
246 {
247  // ASCII only, allow output compression
248  streamOpt.format(IOstreamOption::ASCII);
249 
250  const UList<point>& pointLst = surf.points();
251  const UList<Face>& faceLst = surf.surfFaces();
252  const UList<label>& faceMap = surf.faceMap();
253  const UList<label>& elemIds = surf.faceIds();
254 
255  // for no zones, suppress the group name
256  const surfZoneList zones =
257  (
258  surf.surfZones().empty()
259  ? surfaceFormatsCore::oneZone(faceLst, "")
260  : surf.surfZones()
261  );
262 
263  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
264 
265  // Possible to use faceIds?
266  // - cannot if there are negative ids (eg, encoded solid/side)
267  bool useOrigFaceIds =
268  (
269  !useFaceMap
270  && elemIds.size() == faceLst.size()
271  && !ListOps::found(elemIds, lessOp1<label>(0))
272  );
273 
274  // Not possible with on-the-fly face decomposition
275  if (useOrigFaceIds)
276  {
277  for (const auto& f : faceLst)
278  {
279  if (f.size() > 4)
280  {
281  useOrigFaceIds = false;
282  break;
283  }
284  }
285  }
286 
287 
288  OFstream os(filename, streamOpt);
289  if (!os.good())
290  {
292  << "Cannot write file " << filename << nl
293  << exit(FatalError);
294  }
295 
296 
297  os << "*HEADING" << nl;
298 
299  os << nl
300  << "**" << nl
301  << "** Points" << nl
302  << "**" << nl;
303 
304  writePoints(os, pointLst);
305 
306  os << "**" << nl
307  << "** Faces" << nl
308  << "**" << nl
309  << nl;
310 
311 
312  // Simple tracking for change of element type/set
313  labelPair prevOutput(-1, -1);
314 
315  label faceIndex = 0;
316  label zoneIndex = 0;
317  label elemId = 0;
318 
319  for (const surfZone& zone : zones)
320  {
321  for (label nLocal = zone.size(); nLocal--; ++faceIndex)
322  {
323  const label facei =
324  (useFaceMap ? faceMap[faceIndex] : faceIndex);
325 
326  const Face& f = faceLst[facei];
327 
328  if (useOrigFaceIds)
329  {
330  elemId = elemIds[facei];
331  }
332 
333  const label n = f.size();
334 
335  bool header =
336  (prevOutput.first() != n || prevOutput.second() != zoneIndex);
337 
338  if (header)
339  {
340  // Update values
341  prevOutput.first() = n;
342  prevOutput.second() = zoneIndex;
343  }
344 
345  elemId = writeShell(os, f, elemId, zone.name(), header);
346  }
347 
348  ++zoneIndex;
349  }
350 
351  os << "**" << nl
352  << "**" << nl;
353 }
354 
355 
356 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
Output to file stream as an OSstream, normally using std::ofstream for the actual output...
Definition: OFstream.H:71
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
A simple container for options an IOstream can normally have.
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:220
const pointField & points() const noexcept
Return const access to the points.
const labelUList & faceMap() const noexcept
Const access to the faceMap, zero-sized when unused.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
StringType validate(const std::string &str, const UnaryPredicate &accept, const bool invert=false)
Return a copy of the input string with validated characters.
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
bool useFaceMap() const noexcept
Can/should use faceMap?
virtual bool read(const fileName &filename) override
Read from file.
const UList< surfZone > & surfZones() const noexcept
Const access to the surface zones.
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
static void write(const fileName &filename, const MeshedSurfaceProxy< Face > &surf, IOstreamOption streamOpt=IOstreamOption(), const dictionary &=dictionary::null)
Write surface mesh components (by proxy) in ABAQUS format.
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
Istream and Ostream manipulators taking arguments.
ABAQUSsurfaceFormat()=default
Default construct.
void read(Istream &, label &val, const dictionary &)
In-place read with dictionary lookup.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
OBJstream os(runTime.globalPath()/outputName)
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:75
Input from file stream as an ISstream, normally using std::ifstream for the actual input...
Definition: IFstream.H:51
labelList f(nPoints)
List< word > wordList
List of word.
Definition: fileName.H:59
const labelUList & faceIds() const noexcept
Const access to the faceIds, zero-sized when unused.
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:281
surface1 clear()
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
label n
List< label > labelList
A List of labels.
Definition: List.H:62
const UList< Face > & surfFaces() const noexcept
Return const access to the faces.
Map< label > invertToMap(const labelUList &values)
Create inverse mapping, which is a lookup table into the given list.
Definition: ListOps.C:107
bool found
streamFormat format() const noexcept
Get the current stream format.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28