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