1 /*
2 XLiFE++ is an extended library of finite elements written in C++
3 Copyright (C) 2014 Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 /*!
18 \file mel.cpp
19 \author N. Kielbasiewicz
20 \since 25 mar 2013
21 \date 28 mar 2013
22
23 \brief Implementation of xlifepp::Mesh class members related to input and output mel file format (melina)
24
25 \verbatim
26 * comment line
27 ----------------------------------------------------------------------------
28 TITRE nbligne(s)
29 ...
30 ----------------------------------------------------------------------------
31 [ FORMAT [DE] LECTURE
32 [ [DES] COORDONNEES < ||C*50 ^ '*' > ]
33 [ [DE LA] NUMEROTATION [GLOBALE] < ||C*50 ^ '*' > ]
34 [ < SANS ^ AVEC > COMMENTAIRE ]
35 ]
36 ---------------------------- default values --------------------------------
37 FORMAT DE LECTURE DES COORDONNEES '6E12.4'
38 DE LA NUMEROTATION GLOBALE '18I4'
39 AVEC COMMENTAIRE
40 ----------------------------------------------------------------------------
41 DESCRIPTION GLOBALE [DU] [MAILLAGE]
42 [ [NOM] [DES] VARIABLES [D''] ESPACE : + ||C ]
43 NOMBRE [D''] ELEMENTS : ||I ]
44 --------------------------------- example ----------------------------------
45 DESCRIPTION GLOBALE DU MAILLAGE
46 NOMS DES VARIABLES D''ESPACE : 'X' 'Y' 'Z'
47 NOMBRE D''ELEMENTS : 100
48 ----------------------------------------------------------------------------
49 + BLOC [DE]
50 < < HEXAEDRES ^ PRISMES ^ TETRAEDRES ^ QUADRANGLES ^ TRIANGLES ^ SEGMENTS >
51 DE LAGRANGE [ AUX POINTS DE GAUSS-LOBATTO ]
52 < < P1 ^ Q1 ^ P2 ^ Q2 ^ P3 ^ Q3 ^ Q4 ... Q9 ^ Q10 >
53 ^ < D'ORDRE ^ DE DEGRE > ||I
54 >
55 ^ [TYPE] [GEOMETRIQUE] ||A
56 > : ||IE ELEMENTS
57 --------------------------------- examples ---------------------------------
58 BLOC DE TRIANGLES DE LAGRANGE P2 : 10 ELEMENTS BLOC DE TYPE GEOMETRIQUE TR02 : 10 ELEMENTS
59 QUADRANGLES DE LAGRANGE Q2 : 5 ELEMENTS ou QU02 : 5 ELEMENTS
60 TRIANGLES DE LAGRANGE P2 : 15 ELEMENTS TR02 : 15 ELEMENTS
61 ----------------------------------------------------------------------------
62 X1 Y1 Z1 X2 Y2 Z2 X3 Y3 Z3 .... (coordinates of nodes of element 1)
63 I1 I2 I3 .... (number of nodes of element 1)
64 ...
65 ---------------------------------- example ---------------------------------
66 BLOC DE TRIANGLES DE LAGRANGE P1 : 3 ELEMENTS
67 1.5000 0.0000 1.3858 0.5740 1.0000 0.0000
68 5 6 1
69 0.8660 0.5000 1.0000 0.0000 1.3858 0.5740
70 2 1 6
71 1.3858 0.5740 1.0607 1.0607 0.8660 0.5000
72 6 7 2
73 ----------------------------------------------------------------------------
74 DOMAINE 'nomdomaine'
75 + E[LEMENT] ||I [ / ||J ]
76 + E[LEMENT] ||I1
77 < F[ACE] ||I2 ^ A[RETE] ||I2 ^ P[OINT] ||I2 >
78 --------------------------------- examples ---------------------------------
79 DOMAINE 'OMEGA'
80 E 1 E 3 E 5 E 7 E 8 E 9 equivalent to E 1 3 5 7 ELEMENT 8 9
81 DOMAINE 'OMEGA' ELEMENTS 1 / 7 equivalent to E 1 2 3 4 5 6 7
82 DOMAINE 'GAMMA'
83 ELEMENT 1 FACE 3 ELEMENT 2 FACE 2 ELEMENT 7 FACE 2 equivalent to E 1 F 3 E 2 F 2 E 7 F 2
84 ----------------------------------------------------------------------------
85 FIN
86 \endverbatim
87
88 !!!! WARNING !!!!
89 - do not write more than 80 characters per line ...
90 */
91
92 #include "../Mesh.hpp"
93
94 namespace xlifepp {
95 using std::endl;
96
97
98 // save mesh and related domains to files
saveToMel(const string_t & fname,bool withDomains) const99 void Mesh::saveToMel(const string_t& fname, bool withDomains) const {
100 string_t f = fname + ".mel";
101 std::ofstream out(f.c_str());
102 out.precision(fullPrec);
103 melExport(out);
104 out.close();
105 }
106
107 /*!
108 Write the string str on the output stream out, limiting the length of all
109 output lines to 80 characters
110 Nota: the length of str is logically assumed to be < 80 characters. This is not
111 checked since this is always the case when this function is called by the
112 function melExport ; moreover, this would not produce any error: the string
113 str would just be written as is on a new line.
114
115 ncar is the number of characters previously written on the current line.
116 If the sum of the length of str and ncar does not exceed 80 characters,
117 then str is written at the end of the current line ; otherwise str is
118 written on a new line, which then become the (new) current line.
119 The function returns the updated number of characters written on the current line.
120 */
writeLigne(std::ostream & out,const std::string & str,number_t ncar)121 number_t writeLigne(std::ostream& out, const std::string& str, number_t ncar) {
122 number_t ns=str.size();
123 if (ns+ncar>=80) {
124 out << endl;
125 ncar=0;
126 }
127 out << str;
128 ncar+=ns;
129 return ncar;
130 }
131
melExport(std::ostream & out) const132 void Mesh::melExport(std::ostream& out) const {
133 using std::map;
134 using std::vector;
135 using std::set;
136 using std::ostringstream;
137
138 map<ShapeType, string_t> melNames;
139 melNames[_point] = "PO";
140 melNames[_segment] = "SE";
141 melNames[_triangle] = "TR";
142 melNames[_quadrangle] = "QU";
143 melNames[_tetrahedron] = "TE";
144 melNames[_hexahedron] = "HE";
145 melNames[_prism] = "PR";
146 melNames[_pyramid] = "PY";
147
148 vector<string_t> tl;
149 ostringstream ssti;
150 ssti << "Generated by xlife++ from mesh " << name();
151 string_t ti=ssti.str();
152
153 while (ti.size()>0) {
154 tl.push_back(ti.substr(0,80));
155 ti.erase(0,80);
156 }
157 number_t ntl=tl.size();
158 out << "TITRE " << ntl << endl;
159 for (number_t i=0;i<ntl;i++) {
160 out << tl[i] << endl;
161 }
162
163 out << "FORMAT DE LECTURE DES COORDONNEES '*'" << endl;
164 out << " DE LA NUMEROTATION GLOBALE '*'" << endl;
165 out << " SANS COMMENTAIRE" << endl;
166 out << "DESCRIPTION GLOBALE DU MAILLAGE" << endl;
167 string_t coor;
168 switch (meshDim()) {
169 case 3 : coor = " 'Z'";
170 case 2 : coor = " 'Y'" + coor;
171 case 1 : coor = "'X'" + coor;
172 }
173 out << "NOM DES VARIABLES D''ESPACE : " << coor << endl;
174
175 number_t ne=0;
176 std::multimap<ShapeType,number_t> liElt;
177 vector<ShapeType> liType;
178 set<number_t> liNo;// will contain the node numbers (unique occurrence of each)
179
180 for (vector<GeomDomain*>::const_iterator it_dom=domains().begin();it_dom!=domains().end();it_dom++) {
181 if ((*it_dom)->dim()==spaceDim() && (*it_dom)->domType()==_meshDomain) {
182 MeshDomain* meshDom_p=(*it_dom)->meshDomain();
183 number_t nbEltsInDom = meshDom_p->numberOfElements();
184 ne += nbEltsInDom;
185 for (number_t i=0; i < nbEltsInDom; i++) {
186 ShapeType t = meshDom_p->geomElements[i]->shapeType();
187 if (find(liType.begin(),liType.end(),t)==liType.end()) {
188 liType.push_back(t);
189 }
190 GeomElement* ge_p = meshDom_p->geomElements[i];
191 liElt.insert(std::make_pair(t,ge_p->number()));
192 for (vector<number_t>::const_iterator it=ge_p->meshElement()->nodeNumbers.begin();
193 it!=ge_p->meshElement()->nodeNumbers.end(); it++) { liNo.insert(*it); }
194 }
195 }
196 }
197 // noNo will contain the correspondence between the node numbers and the numbers to be used
198 // in the file, which should be a continuous sequence of integers starting from 1
199 map<number_t,number_t> noNo;
200 number_t newNo=1;
201 for (set<number_t>::const_iterator it=liNo.begin(); it != liNo.end(); it++) {
202 noNo[*it] = newNo++;
203 }
204 liNo.clear();
205
206 // write element of mesh dimension by type
207 out << "NOMBRE D''ELEMENTS : " << ne << endl;
208 // element type list
209 string_t com="BLOC DE TYPE GEOMETRIQUE ";
210 for (size_t i=0; i<liType.size(); i++) {
211 ShapeType t = liType[i];
212 number_t nt = liElt.count(t);
213 out << com << melNames[t];
214 if (order()<=9) { out << "0";}
215 out << order() << " : " << nt << " ELEMENTS" << endl;
216 }
217
218 vector<number_t> renumbering(nbOfElements()+1);// first element unused
219 // coordinates and indices of all elements of dimension dim, sorted by type
220 number_t elNo=0; // for the reindexing of elements (continuous sequence of integers starting from 1)
221
222 typedef std::multimap<ShapeType,number_t>::iterator it_m;
223 for (number_t i=0; i<liType.size(); i++) {
224 std::pair<it_m,it_m> pit=liElt.equal_range(liType[i]);
225
226 for (it_m jt=pit.first; jt!=pit.second; ++jt) {
227 number_t elNum = jt->second;
228 renumbering[elNum] = ++elNo;
229 const GeomElement& geomElt = element(elNum);
230 if (geomElt.hasMeshElement()) {
231 for (number_t j=0; j<geomElt.numberOfNodes(); j++) {
232 number_t ncar=0;
233 for (number_t k=0; k<geomElt.elementDim(); k++) {
234 ostringstream ss;
235 ss << (*geomElt.meshElement()->nodes[j])[k] << " ";
236 ncar = writeLigne(out,ss.str(),ncar);
237 }
238 }
239 out << endl;
240 number_t ncar=0;
241 for (number_t j=0; j<geomElt.numberOfNodes(); j++) {
242 ostringstream ss;
243 ss << noNo[geomElt.meshElement()->nodeNumbers[j]] << " ";
244 ncar = writeLigne(out,ss.str(),ncar);
245 }
246 }
247 out << endl;
248 }
249 }
250
251 // list of domains (multi dimensional domain are not processed !)
252 for (vector<GeomDomain*>::const_iterator it_dom=domains().begin(); it_dom!=domains().end(); it_dom++) {
253 out << "DOMAINE " << "\'" << (*it_dom)->name() << "\'" << endl;
254 if ((*it_dom)->domType()==_meshDomain) {
255 MeshDomain* meshDom_p=(*it_dom)->meshDomain();
256 number_t nbEltsInDom = meshDom_p->numberOfElements();
257
258 if ((*it_dom)->dim()==meshDim() && (*it_dom)->domType()==_meshDomain ) { // mesh.dim domain
259 out << "ELEMENT ";
260 number_t ncar=8, lastEl;
261 for (number_t i=0; i<nbEltsInDom; i++) {
262 ostringstream ss ;
263 lastEl = renumbering[meshDom_p->geomElements[i]->number()];
264 ss << lastEl << " ";
265 ncar = writeLigne(out,ss.str(),ncar);
266 }
267 if (nbEltsInDom == 1) { out << "/ " << lastEl; }// This allows correct reading of the file, which fails without that.
268 out << endl;
269 }
270
271 dimen_t domdim = meshDom_p->dim();
272 if (domdim == meshDim()-1) { // mesh.dim-1 domain
273 string_t bord;
274 switch (domdim) {
275 case 2 : bord="F"; break;
276 case 1 : bord="A"; break;
277 case 0 : bord="P"; break;
278 default:
279 error("domain_dim_not_handled",domdim);
280 }
281
282 number_t ncar=0;
283 for (number_t i=0; i<nbEltsInDom; i++) {
284 vector<GeoNumPair>::iterator it_gnp=meshDom_p->geomElements[i]->parentSides().begin();
285 ostringstream ss;
286 ss << "E " << it_gnp->first->number() << " " << bord << " " << it_gnp->second << " ";
287 ncar = writeLigne(out,ss.str(),ncar);
288 }
289 out << endl;
290 }
291 }
292 }
293
294 // end of mel file
295 out << "FIN" << endl;
296 }
297
298 } // end of namespace xlifepp
299