1 /****************************************************************************/
2 /* This file is part of FreeFEM. */
3 /* */
4 /* FreeFEM is free software: you can redistribute it and/or modify */
5 /* it under the terms of the GNU Lesser General Public License as */
6 /* published by the Free Software Foundation, either version 3 of */
7 /* the License, or (at your option) any later version. */
8 /* */
9 /* FreeFEM 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 Lesser General Public License for more details. */
13 /* */
14 /* You should have received a copy of the GNU Lesser General Public License */
15 /* along with FreeFEM. If not, see <http://www.gnu.org/licenses/>. */
16 /****************************************************************************/
17 // SUMMARY : ...
18 // LICENSE : LGPLv3
19 // ORG : LJLL Universite Pierre et Marie Curie, Paris, FRANCE
20 // AUTHORS : Sala Lorenzo
21 // E-MAIL : salallo80@gmail.com
22
23 /* clang-format off */
24 //ff-c++-LIBRARY-dep:
25 //ff-c++-cpp-dep:
26 /* clang-format on */
27
28 #include "mode_open.hpp"
29 #include <iostream>
30 #include <cfloat>
31 #include <cmath>
32 #include <iterator>
33 using namespace std;
34 #include "ff++.hpp"
35 using namespace Fem2D;
36
37 /*!The class DxWriter permits to save in opendx format a "field"
38 * (in the dx-language a "field" means the values of a function f(x,y,z) on a grid),
39 * a time series (an ordered collection of "fields", so we have field0=f(x,y,z,t0),
40 * field1=f(x,y,z,t1) and so on). DxWriter creates two files: one with extension .data where it puts
41 * the position of the grid, the connessions, the values; and one with extension.dx where it puts
42 * the time series. Now you can save only scalar fields. An example <code> load "DxWriter" mesh
43 * Th=square(5,5); DxWriter ff("pippo"); Dxaddmesh(ff, Th); Dxaddtimeseries(ff, "Vx",Th); fespace
44 * Vh(Th, P1); Vh vx=x*y; Dxaddsol2ts(ff,"Vx",1.0, vx); vx=0.5*x*y^2+0.2; Dxaddsol2ts(ff,"Vx",2.0,
45 * vx); cout<<"Ciao";
46 * </code>
47 */
48
49 class DxWriter {
50 struct tsinfo {
51 int imesh; //!< index of the mesh
52 std::string name;
53 std::vector< double > vecistant;
54 };
55
56 private:
57 std::vector< const Fem2D::Mesh * > _vecmesh;
58 std::vector< tsinfo > _vecofts;
59 std::string _nameoffile;
60 /*! This string contains the name of data file with \\ where there's a \ in the path*/
61 std::string _nameofdatafile;
62 //! files containing the data and the timeseries
63 std::ofstream _ofdata, _ofts;
64
65 /*!This function is called frequently, so if the main program crashes the files are good
66 * and you need only write "end" at the end of data file: echo end>>nameoffile.data and then the
67 * files are good
68 */
save_header()69 void save_header( ) {
70 std::string s = _nameoffile;
71
72 s.append(".dx");
73 _ofts.open(s.c_str( ), std::ios_base::out);
74
75 for (int i = 0; i < _vecofts.size( ); ++i) {
76 _ofts << "object \"" << _vecofts[i].name << "\" class series" << std::endl;
77
78 for (int j = 0; j < _vecofts[i].vecistant.size( ); ++j) {
79 _ofts << "member " << j << " value file \"" << _nameofdatafile << "\",\""
80 << _vecofts[i].name << "_" << j << "\" position " << _vecofts[i].vecistant[j]
81 << std::endl;
82 }
83
84 _ofts << std::endl;
85 }
86
87 _ofts << "end" << std::endl;
88 _ofts.close( );
89 }
90
91 public:
DxWriter()92 DxWriter( ) { std::cout << "Constructor of DxWriter" << endl; }
93
openfiles(const std::string & s)94 void openfiles(const std::string &s) {
95 _nameoffile = s;
96 std::string tmp = s + ".data";
97 std::cout << tmp << " ";
98 _ofdata.open(tmp.c_str( ), std::ios_base::out);
99 _nameofdatafile = "";
100
101 for (int i = 0; i < tmp.length( ); ++i) {
102 if (tmp.at(i) == '\\') {
103 _nameofdatafile.append(1, '\\');
104 }
105
106 _nameofdatafile.append(1, tmp.at(i));
107 }
108 }
109
addmesh(const Fem2D::Mesh * mesh)110 void addmesh(const Fem2D::Mesh *mesh) {
111 const Fem2D::Mesh &Th(*mesh);
112
113 _vecmesh.push_back(mesh);
114 _ofdata.flags(std::ios_base::scientific);
115 _ofdata.precision(15);
116 _ofdata << "object \"pos_" << _vecmesh.size( ) - 1
117 << "\" class array type float rank 1 shape 2 items " << Th.nv << " data follows"
118 << std::endl;
119
120 for (int k = 0; k < Th.nv; ++k) { // Scorre tutti i vertici
121 _ofdata << Th(k).x << " " << Th(k).y << endl;
122 }
123
124 _ofdata << std::endl;
125 _ofdata.flags(std::ios_base::fixed);
126 _ofdata << "object \"conn_" << _vecmesh.size( ) - 1
127 << "\" class array type int rank 1 shape 3 items " << Th.nt << " data follows " << endl;
128
129 for (int i = 0; i < Th.nt; i++) {
130 for (int j = 0; j < 3; j++) {
131 _ofdata << Th(i, j) << " ";
132 }
133
134 _ofdata << endl;
135 }
136
137 _ofdata << "attribute \"element type\" string \"triangles\" " << std::endl;
138 _ofdata << "attribute \"ref\" string \"positions\" " << std::endl << std::endl;
139 }
140
141 /*!Add a new time series, defined on the mesh*/
addtimeseries(const string & nameofts,const Fem2D::Mesh * mesh)142 void addtimeseries(const string &nameofts, const Fem2D::Mesh *mesh) {
143 tsinfo ts;
144
145 ts.name = nameofts;
146 std::vector< const Fem2D::Mesh * >::const_iterator first = _vecmesh.begin( ),
147 last = _vecmesh.end( );
148
149 if (std::find(first, last, mesh) == last) {
150 addmesh(mesh);
151 ts.imesh = _vecmesh.size( ) - 1;
152 } else {
153 ts.imesh = std::distance(first, std::find(first, last, mesh));
154 }
155
156 _vecofts.push_back(ts);
157 }
158
159 /*!Add an instant to a time series name*/
addistant2ts(const string & nameofts,const double t,const KN<double> & val)160 void addistant2ts(const string &nameofts, const double t, const KN< double > &val) {
161 int jj = -1;
162
163 for (int i = 0; i < _vecofts.size( ); ++i) {
164 if (_vecofts[i].name == nameofts) {
165 jj = i;
166 }
167 }
168
169 _vecofts[jj].vecistant.push_back(t);
170 _ofdata.flags(std::ios_base::scientific);
171 _ofdata.precision(15);
172 _ofdata << "object \"" << nameofts << "_data_" << _vecofts[jj].vecistant.size( ) - 1
173 << "\" class array type float rank 0 items " << val.size( ) << " data follows"
174 << std::endl;
175
176 for (int i = 0; i < val.size( ); ++i) {
177 _ofdata << val[i] << std::endl;
178 }
179
180 _ofdata << "attribute \"dep\" string \"positions\"" << std::endl << std::endl;
181 _ofdata << "object \"" << nameofts << "_" << _vecofts[jj].vecistant.size( ) - 1
182 << "\" class field" << std::endl;
183 _ofdata << "component \"positions\" value \"pos_" << _vecofts[jj].imesh << "\"" << std::endl;
184 _ofdata << "component \"connections\" value \"conn_" << _vecofts[jj].imesh << "\"" << std::endl;
185 _ofdata << "component \"data\" value \"" << nameofts << "_data_"
186 << _vecofts[jj].vecistant.size( ) - 1 << "\"" << std::endl
187 << std::endl;
188 _ofdata.flush( );
189 save_header( );
190 }
191
192 /*!Add a field*/
addfield(const string & nameoffield,const Fem2D::Mesh * mesh,const KN<double> & val)193 void addfield(const string &nameoffield, const Fem2D::Mesh *mesh, const KN< double > &val) {
194 std::vector< const Fem2D::Mesh * >::const_iterator first = _vecmesh.begin( ),
195 last = _vecmesh.end( );
196 int im;
197
198 if (std::find(first, last, mesh) == last) {
199 addmesh(mesh);
200 im = _vecmesh.size( ) - 1;
201 } else {
202 im = std::distance(first, std::find(first, last, mesh));
203 }
204
205 _ofdata.flags(std::ios_base::scientific);
206 _ofdata.precision(15);
207 _ofdata << "object \"" << nameoffield << "_data\" class array type float rank 0 items "
208 << val.size( ) << " data follows" << std::endl;
209
210 for (int i = 0; i < val.size( ); ++i) {
211 _ofdata << val[i] << std::endl;
212 }
213
214 _ofdata << "attribute \"dep\" string \"positions\"" << std::endl << std::endl;
215 _ofdata << "object \"" << nameoffield << "\" class field" << std::endl;
216 _ofdata << "component \"positions\" value \"pos_" << im << "\"" << std::endl;
217 _ofdata << "component \"connections\" value \"conn_" << im << "\"" << std::endl;
218 _ofdata << "component \"data\" value \"" << nameoffield << "_data\"" << std::endl << std::endl;
219 _ofdata.flush( );
220 }
221
222 /*!Get the mesh associated with the series nameofts*/
getmeshts(const string & nameofts)223 const Fem2D::Mesh *getmeshts(const string &nameofts) {
224 for (int i = 0; i < _vecofts.size( ); ++i) {
225 if (_vecofts[i].name == nameofts) {
226 return _vecmesh[_vecofts[i].imesh];
227 }
228 }
229
230 return NULL;
231 }
232
init()233 void init( ) { new (this) DxWriter( ); }
234
destroy()235 void destroy( ) {
236 if (_ofdata.is_open( )) {
237 _ofdata << std::endl << "end" << std::endl;
238 _ofdata.close( );
239 }
240 }
241 };
242
243 class Dxwritesol_Op : public E_F0mps {
244 public:
245 typedef long Result;
246 Expression edx;
247 Expression ename; //!< name of time series or field
248 Expression et; //!< time
249 long what; // 1 scalar, 2 vector, 3 symtensor
250 long nbfloat; // 1 scalar, n vector (3D), n symtensor(3D)
251 Expression evct;
252
253 public:
Dxwritesol_Op(const basicAC_F0 & args)254 Dxwritesol_Op(const basicAC_F0 &args) : what(0), nbfloat(0) {
255 evct = 0;
256 // There's no named parameter
257 args.SetNameParam( );
258 if (args.size( ) != 4) {
259 CompileError("Dxwritesol accepts only 4 parameters");
260 }
261
262 if (BCastTo< DxWriter * >(args[0])) {
263 edx = CastTo< DxWriter * >(args[0]);
264 }
265
266 if (BCastTo< string * >(args[1])) {
267 ename = CastTo< string * >(args[1]);
268 }
269
270 if (BCastTo< double >(args[2])) {
271 et = CastTo< double >(args[2]);
272 }
273
274 if (args[3].left( ) == atype< double >( )) {
275 what = 1;
276 nbfloat = 1;
277 evct = to< double >(args[3]);
278 } else if (args[3].left( ) == atype< double * >( )) {
279 what = 1;
280 nbfloat = 1;
281 evct = to< double >(args[3]);
282 } else if (BCastTo< pfer >(args[3])) {
283 what = 1;
284 nbfloat = 1;
285 evct = to< double >(args[3]);
286 } else if (args[3].left( ) == atype< E_Array >( )) {
287 CompileError("Until now only scalar solution");
288 } else {
289 CompileError("savesol in 2D: Sorry no way to save this kind of data");
290 }
291 }
292
typeargs()293 static ArrayOfaType typeargs( ) {
294 return ArrayOfaType(atype< DxWriter * >( ), atype< string * >( ), atype< double >( ), true);
295 } // all type
296
f(const basicAC_F0 & args)297 static E_F0 *f(const basicAC_F0 &args) { return new Dxwritesol_Op(args); }
298
299 AnyType operator( )(Stack stack) const;
300 };
301
operator ( )(Stack stack) const302 AnyType Dxwritesol_Op::operator( )(Stack stack) const {
303 MeshPoint *mp(MeshPointStack(stack));
304 DxWriter &dx = *(GetAny< DxWriter * >((*edx)(stack)));
305 string &name = *(GetAny< string * >((*ename)(stack)));
306 double t = GetAny< double >((*et)(stack));
307 const Mesh &Th = *(dx.getmeshts(name));
308 int nt = Th.nt;
309 int nv = Th.nv;
310 int nbsol = nv;
311 long longdefault = 0;
312
313 KN< double > valsol(nbsol);
314 valsol = 0.;
315 KN< int > takemesh(nbsol);
316 takemesh = 0;
317 MeshPoint *mp3(MeshPointStack(stack));
318
319 for (int it = 0; it < nt; it++) {
320 for (int iv = 0; iv < 3; iv++) {
321 int i = Th(it, iv);
322 mp3->setP(&Th, it, iv);
323 valsol[i] = valsol[i] + GetAny< double >((*evct)(stack));
324 ++takemesh[i];
325 }
326 }
327
328 for (int i = 0; i < nbsol; i++) {
329 valsol[i] /= takemesh[i];
330 }
331
332 // Writes valsol on the file file
333 dx.addistant2ts(name, t, valsol);
334
335 return longdefault;
336 }
337
338 // le vrai constructeur est la
init_DxWriter(DxWriter * const & a,string * const & s)339 DxWriter *init_DxWriter(DxWriter *const &a, string *const &s) {
340 std::cout << "start init_DxWriter" << std::endl;
341
342 a->init( );
343 a->openfiles(*s);
344 std::cout << "end init_DxWriter" << std::endl;
345 return a;
346 }
347
call_addmesh(DxWriter * const & mt,const Fem2D::Mesh * const & pTh)348 void *call_addmesh(DxWriter *const &mt, const Fem2D::Mesh *const &pTh) {
349 mt->addmesh(pTh);
350 return NULL;
351 }
352
call_addtimeseries(DxWriter * const & mt,string * const & name,const Fem2D::Mesh * const & pTh)353 void *call_addtimeseries(DxWriter *const &mt, string *const &name, const Fem2D::Mesh *const &pTh) {
354 mt->addtimeseries(*name, pTh);
355 return NULL;
356 }
357
358 // Add the function name to the freefem++ table
Load_Init()359 static void Load_Init( ) {
360 Dcl_Type< DxWriter * >(
361 InitP< DxWriter >,
362 Destroy< DxWriter >); // declare deux nouveau type pour freefem++ un pointeur et
363
364 zzzfff->Add("DxWriter", atype< DxWriter * >( )); // ajoute le type myType a freefem++
365 // constructeur d'un type myType dans freefem
366 TheOperators->Add("<-", new OneOperator2_< DxWriter *, DxWriter *, string * >(&init_DxWriter));
367
368 Global.Add("Dxaddmesh", "(",
369 new OneOperator2_< void *, DxWriter *, const Fem2D::Mesh * >(call_addmesh));
370 Global.Add("Dxaddtimeseries", "(",
371 new OneOperator3_< void *, DxWriter *, std::string *, const Fem2D::Mesh * >(
372 call_addtimeseries));
373
374 Global.Add("Dxaddsol2ts", "(", new OneOperatorCode< Dxwritesol_Op >);
375
376 // atype< myType * >()->Add("(","",new OneOperator3_<myType_uv,myType *,double,double
377 // >(set_myType_uv));
378 }
379
380 LOADFUNC(Load_Init)
381