Guest User

Untitled

a guest
Mar 19th, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.66 KB | None | 0 0
  1. #include <iostream>
  2. #include <fstream>
  3. #include <cassert>
  4.  
  5. #include "mfem.hpp"
  6.  
  7. extern "C" {
  8. #include "xf.h"
  9. #include "xf_All.h"
  10. #include "xf_Mesh.h"
  11. #include "xf_Basis.h"
  12. #include "xf_Data.h"
  13. #include "xf_State.h"
  14. #include "xf_Math.h"
  15. }
  16.  
  17. // Convert XFlow shapes to MFEM geometry
  18. mfem::Geometry::Type ShapeToGeometry(enum xfe_ShapeType shape)
  19. {
  20. switch (shape)
  21. {
  22. case xfe_Point : return mfem::Geometry::POINT;
  23. case xfe_Segment : return mfem::Geometry::SEGMENT;
  24. case xfe_Triangle : return mfem::Geometry::TRIANGLE;
  25. case xfe_Quadrilateral : return mfem::Geometry::SQUARE;
  26. case xfe_Hexahedron : return mfem::Geometry::CUBE;
  27. case xfe_Tetrahedron : return mfem::Geometry::TETRAHEDRON;
  28. default: throw std::runtime_error("Unknown shape");
  29. }
  30. }
  31.  
  32. void ReverseIntArray(const int *input, int size, int *output)
  33. {
  34. for (int i = 0; i < size; i++) output[input[i]] = i;
  35. }
  36.  
  37. mfem::GridFunction convertXFVector(const xf_Mesh *xflow_mesh,
  38. mfem::Mesh *mesh,
  39. const xf_Vector *V)
  40. {
  41. int ierr;
  42. const int vdim = V->StateRank;
  43. const int dim = xflow_mesh->Dim;
  44.  
  45. // Make sure the vector is interpolated
  46. if (V->Order == NULL) throw std::runtime_error("Data is not interpolated");
  47.  
  48. // ... and has element linkage
  49. if (V->Linkage != xfe_LinkageGlobElem) throw std::runtime_error("Is not implemented for non-element-linked data");
  50.  
  51. // ... and that the number of element groups equals the number of arrays
  52. if (V->nArray != xflow_mesh->nElemGroup) throw std::runtime_error("Need number of elements groups to match number of arrays");
  53.  
  54. // Find max order
  55. int max_order = 0;
  56. for (int array = 0; array < V->nArray; array++)
  57. {
  58. if (V->vOrder == NULL)
  59. {
  60. const int order = V->Order[array];
  61. max_order = order > max_order ? order : max_order;
  62. }
  63. else
  64. {
  65. for (int comp = 0; comp < V->nComp[array]; comp++)
  66. {
  67. const int order = V->vOrder[array][comp];
  68. max_order = order > max_order ? order : max_order;
  69. }
  70. }
  71. }
  72.  
  73. enum xfe_ShapeType elem_shape;
  74. ierr = xf_Error(xf_Basis2Shape(xflow_mesh->ElemGroup[0].QBasis, &elem_shape));
  75. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  76.  
  77. // elem_basis is the basis of the solution _not_ necessarily that of the mesh
  78. enum xfe_BasisType elem_basis;
  79. ierr = xf_Error(xf_Shape2UniformLagrange(elem_shape, &elem_basis));
  80. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  81.  
  82. int nn;
  83. ierr = xf_Error(xf_Order2nNode(elem_basis, max_order, &nn));
  84. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  85.  
  86. mfem::L2_FECollection *fec = new mfem::L2_FECollection(max_order, xflow_mesh->Dim, mfem::BasisType::ClosedUniform);
  87. mfem::FiniteElementSpace *fes = new mfem::FiniteElementSpace(mesh, fec, vdim, mfem::Ordering::byVDIM);
  88. mfem::GridFunction gf(fes);
  89. // TODO make sure fec gets deleted somehow...
  90. // gf.MakeOwner(fec); // gf will destroy 'fec' and 'fes'
  91.  
  92. // Create a temporary data set
  93. xf_DataSet *DataSet;
  94. ierr = xf_Error(xf_CreateDataSet(&DataSet));
  95. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  96.  
  97. // This is the same operation as filling the mesh Nodes
  98. // GridFunction, but it cannot be reused since xflow does not expose
  99. // these as an xf_Vector.
  100. mfem::Array<int> vdofs;
  101. xf_Matrix *T = NULL;
  102. for (int egrp = 0; egrp < V->nArray; egrp++)
  103. {
  104. xf_GenArray &GA = V->GenArray[egrp];
  105.  
  106. for (int elem = 0; elem < GA.n; elem++)
  107. {
  108. const enum xfe_BasisType basis = (V->Basis != NULL) ? V->Basis[egrp] : V->vBasis[egrp][elem];
  109. const int order = (V->vOrder != NULL) ? V->vOrder[egrp][elem] : V->Order[egrp];
  110.  
  111. fes->GetElementVDofs(elem, vdofs);
  112. const mfem::FiniteElement *fe = fes->GetFE(elem);
  113. const int ndof = fe->GetDof();
  114.  
  115. // Assumption: element data (so, use elem_shape from above)
  116. mfem::Array<double> values;
  117. if (order != max_order)
  118. {
  119. // Variable order - need to find a transfer matrix in XFlow
  120. ierr = xf_Error(xf_FindTransferMatrix(DataSet, basis, order, elem_basis, max_order, &T));
  121. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  122.  
  123. int ndof_e;
  124. ierr = xf_Error(xf_Order2nNode(basis, order, &ndof_e));
  125. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  126.  
  127. values.SetSize(ndof_e * ndof);
  128.  
  129. xf_MxM_Set(T->GenArray[0].rValue[0], GA.rValue[elem], ndof, ndof_e, vdim, values);
  130. }
  131. else
  132. {
  133. values.MakeRef(GA.rValue[elem], ndof * vdim);
  134. }
  135.  
  136. // The ordering of MFEM grid functions is _almost_ the same as
  137. // XFlow (both store lexicographically) but MFEM stores vdofs
  138. // byNODES so we need to loop over the dimensions manually:
  139. for (int i = 0; i < ndof; i++) {
  140. for (int vd = 0; vd < vdim; vd++) {
  141. gf(vdofs[i+ndof*vd]) = values[i * vdim + vd];
  142. // This is the syntax if we had to map:
  143. // gf(dofs[dof_map[i]]*vdim + vd) = values[i * dim + vd];
  144. }
  145. }
  146. // If the ordering where the same we could simply use this:
  147. // gf.SetSubVector(vdofs, values);
  148. }
  149. }
  150.  
  151. ierr = xf_Error(xf_DestroyDataSet(DataSet));
  152. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  153.  
  154. return gf;
  155. }
  156.  
  157. class NodeHash
  158. {
  159. private:
  160. std::vector<int> forward;
  161. std::vector<int> reverse; // indexed by node
  162.  
  163. public:
  164. NodeHash() : forward(), reverse() { }
  165.  
  166. int add(int node) // Returns the tag
  167. {
  168. if (reverse.size() < node+1)
  169. {
  170. reverse.resize(node+1, -1);
  171. }
  172.  
  173. int tag = reverse[node];
  174. if (tag < 0)
  175. {
  176. reverse[node] = forward.size();
  177. forward.push_back(node);
  178. }
  179.  
  180. return tag;
  181. }
  182.  
  183. int get(int tag) const
  184. {
  185. return forward[tag];
  186. }
  187.  
  188. int size() const
  189. {
  190. return forward.size();
  191. }
  192. };
  193.  
  194. class XFMesh : public mfem::Mesh
  195. {
  196. public:
  197. XFMesh(xf_Mesh &xflow_mesh);
  198. };
  199.  
  200. XFMesh::XFMesh(xf_Mesh &xflow_mesh) : mfem::Mesh()
  201. {
  202. int ierr;
  203. std::vector<int> dof_map_rev, verts, fvec;
  204.  
  205. // Count elements
  206. int nElemTot = 0;
  207. for (int egrp = 0; egrp < xflow_mesh.nElemGroup; egrp++)
  208. {
  209. nElemTot += xflow_mesh.ElemGroup[egrp].nElem;
  210. }
  211.  
  212. // Count boundary elements
  213. int nBdrElem = 0;
  214. for (int bfgrp = 0; bfgrp < xflow_mesh.nBFaceGroup; bfgrp++)
  215. {
  216. nBdrElem += xflow_mesh.BFaceGroup[bfgrp].nBFace;
  217. }
  218.  
  219. const int dim = xflow_mesh.Dim;
  220.  
  221. // Check whether or not QOrder changes. If so, we cannot
  222. // represent the mesh nodes by a simple H1 grid function.
  223. int pQOrder = xflow_mesh.ElemGroup[0].QOrder;
  224. bool QOrderChanges = false;
  225. int MaxQOrder = pQOrder;
  226. for (int egrp = 1; egrp < xflow_mesh.nElemGroup; egrp++)
  227. {
  228. QOrderChanges |= (xflow_mesh.ElemGroup[egrp].QOrder != pQOrder);
  229. MaxQOrder = max(xflow_mesh.ElemGroup[egrp].QOrder, MaxQOrder);
  230. }
  231. if (QOrderChanges)
  232. {
  233. std::cout << "QOrder changes - will not curve mesh. In the future this function could determine the high order nodes on the low order elements." << std::endl;
  234. }
  235.  
  236. // Create a FiniteElementCollection early on for dof_map access
  237. // dof_map = Cartesian to local H1 dof map
  238. mfem::H1_FECollection *fec = new mfem::H1_FECollection(MaxQOrder, dim);
  239.  
  240. // Node hash to get the vertex ordering
  241. NodeHash nh;
  242. for (int egrp = 0; egrp < xflow_mesh.nElemGroup; egrp++)
  243. {
  244. const xf_ElemGroup &EG = xflow_mesh.ElemGroup[egrp];
  245.  
  246. enum xfe_ShapeType shape;
  247. ierr = xf_Basis2Shape(EG.QBasis, &shape);
  248. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  249.  
  250. const int geom_type = ShapeToGeometry(shape);
  251. const int *dof_map = fec->GetDofMap(geom_type);
  252. const mfem::FiniteElement *fe = fec->FiniteElementForGeometry(geom_type);
  253. const int num_dof = fe->GetDof();
  254. dof_map_rev.resize(num_dof);
  255. ReverseIntArray(dof_map, num_dof, dof_map_rev.data());
  256.  
  257. const int num_verts = mfem::Geometry::NumVerts[geom_type];
  258. for (int elem = 0; elem < EG.nElem; elem++)
  259. {
  260. for (int i = 0; i < num_verts; i++)
  261. {
  262. nh.add(EG.Node[elem][dof_map_rev[i]]);
  263. }
  264. }
  265. }
  266.  
  267. InitMesh(dim, dim, nh.size(), nElemTot, nBdrElem);
  268.  
  269. // 1. Add the vertices
  270. for (int i = 0; i < nh.size(); i++)
  271. {
  272. const int node = nh.get(i);
  273. AddVertex(xflow_mesh.Coord[node]);
  274. }
  275. NumOfVertices = nh.size();
  276.  
  277. // 2. Add the elements
  278. int egrp_offset = 0;
  279. for (int egrp = 0; egrp < xflow_mesh.nElemGroup; egrp++)
  280. {
  281. const xf_ElemGroup &EG = xflow_mesh.ElemGroup[egrp];
  282. mfem::Element **elements_egrp = elements.GetData() + egrp_offset;
  283.  
  284. enum xfe_ShapeType shape;
  285. ierr = xf_Basis2Shape(EG.QBasis, &shape);
  286. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  287.  
  288. switch (shape)
  289. {
  290. case xfe_Segment:
  291. for (int e = 0; e < EG.nElem; e++) elements_egrp[e] = new mfem::Segment();
  292. break;
  293. case xfe_Quadrilateral:
  294. for (int e = 0; e < EG.nElem; e++) elements_egrp[e] = new mfem::Quadrilateral();
  295. break;
  296. case xfe_Triangle:
  297. for (int e = 0; e < EG.nElem; e++) elements_egrp[e] = new mfem::Triangle();
  298. break;
  299. case xfe_Hexahedron:
  300. for (int e = 0; e < EG.nElem; e++) elements_egrp[e] = new mfem::Hexahedron();
  301. break;
  302. case xfe_Tetrahedron:
  303. for (int e = 0; e < EG.nElem; e++) elements_egrp[e] = new mfem::Tetrahedron();
  304. break;
  305. }
  306.  
  307. const int geom_type = ShapeToGeometry(shape);
  308. const int *dof_map = fec->GetDofMap(geom_type);
  309. const mfem::FiniteElement *fe = fec->FiniteElementForGeometry(geom_type);
  310. const int num_dof = fe->GetDof();
  311. dof_map_rev.resize(num_dof);
  312. ReverseIntArray(dof_map, num_dof, dof_map_rev.data());
  313.  
  314. const int num_verts = mfem::Geometry::NumVerts[geom_type];
  315. verts.resize(num_verts);
  316. for (int elem = 0; elem < EG.nElem; elem++)
  317. {
  318. for (int i = 0; i < num_verts; i++)
  319. {
  320. verts[i] = nh.add(EG.Node[elem][dof_map_rev[i]]);
  321. }
  322. elements_egrp[elem]->SetVertices(verts.data());
  323. elements_egrp[elem]->SetAttribute(1 + egrp);
  324. }
  325.  
  326. egrp_offset += EG.nElem;
  327. }
  328. NumOfElements = egrp_offset;
  329.  
  330. // 3. Add the boundary elements
  331. int bfgrp_offset = 0;
  332. for (int bfgrp = 0; bfgrp < xflow_mesh.nBFaceGroup; bfgrp++)
  333. {
  334. xf_BFaceGroup &BFG = xflow_mesh.BFaceGroup[bfgrp];
  335.  
  336. mfem::Element **boundary_bfgrp = boundary.GetData() + bfgrp_offset;
  337.  
  338. for (int bface = 0; bface < BFG.nBFace; bface++)
  339. {
  340. // Every element in the boundary face group may have a different
  341. // shape or derive from an element of different QOrder, hence
  342. // the allocation needs to happen inside the loop over bface.
  343.  
  344. const xf_BFace &BF = BFG.BFace[bface];
  345. const xf_ElemGroup &EG = xflow_mesh.ElemGroup[BF.ElemGroup];
  346.  
  347. enum xfe_ShapeType elem_shape, face_shape;
  348. ierr = xf_Basis2Shape(EG.QBasis, &elem_shape);
  349. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  350. ierr = xf_FaceShape(elem_shape, BF.Face, &face_shape);
  351. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  352.  
  353. switch (face_shape)
  354. {
  355. case xfe_Point:
  356. boundary_bfgrp[bface] = new mfem::Point();
  357. break;
  358. case xfe_Segment:
  359. boundary_bfgrp[bface] = new mfem::Segment();
  360. break;
  361. case xfe_Quadrilateral:
  362. boundary_bfgrp[bface] = new mfem::Quadrilateral();
  363. break;
  364. case xfe_Triangle:
  365. boundary_bfgrp[bface] = new mfem::Triangle();
  366. break;
  367. }
  368.  
  369. const int geom_type = ShapeToGeometry(face_shape);
  370. const mfem::FiniteElement *fe = fec->FiniteElementForGeometry(geom_type);
  371. int num_dof;
  372. if (geom_type != mfem::Geometry::POINT)
  373. {
  374. const int *dof_map = fec->GetDofMap(geom_type);
  375. num_dof = fe->GetDof();
  376. ReverseIntArray(dof_map, num_dof, dof_map_rev.data());
  377. }
  378. else
  379. {
  380. const int dof_map[1] = {0};
  381. num_dof = 1;
  382. ReverseIntArray(dof_map, num_dof, dof_map_rev.data());
  383. }
  384. dof_map_rev.resize(num_dof);
  385.  
  386. const int num_verts = mfem::Geometry::NumVerts[geom_type];
  387.  
  388. int nqnode;
  389. fvec.resize(num_dof);
  390. ierr = xf_NodesOnFace(EG.QBasis, EG.QOrder, BF.Face, &nqnode, fvec.data());
  391. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  392.  
  393. verts.resize(num_verts);
  394. for (int i = 0; i < num_verts; i++)
  395. {
  396. verts[i] = nh.add(EG.Node[BF.Elem][fvec[dof_map_rev[i]]]);
  397. }
  398. boundary_bfgrp[bface]->SetVertices(verts.data());
  399. boundary_bfgrp[bface]->SetAttribute(1 + bfgrp);
  400. }
  401.  
  402. bfgrp_offset += BFG.nBFace;
  403. }
  404. NumOfBdrElements = bfgrp_offset;
  405.  
  406. FinalizeTopology();
  407.  
  408. if (MaxQOrder == 1) return;
  409.  
  410. // --- Set curvature to MaxQOrder ---
  411.  
  412. // The method below works, but it does extra work
  413. // SetCurvature(MaxQOrder, false, dim, mfem::Ordering::byVDIM);
  414.  
  415. // Adding back the Q1 nodes manually is much more efficient
  416. mfem::FiniteElementSpace *fes = new mfem::FiniteElementSpace(this, fec, dim,
  417. mfem::Ordering::byVDIM);
  418. Nodes = new mfem::GridFunction(fes);
  419. Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
  420. own_nodes = 1;
  421.  
  422. mfem::Array<int> dofs;
  423. for (int egrp = 0; egrp < xflow_mesh.nElemGroup; egrp++)
  424. {
  425. xf_ElemGroup &EG = xflow_mesh.ElemGroup[egrp];
  426. enum xfe_ShapeType shape;
  427.  
  428. ierr = xf_Basis2Shape(EG.QBasis, &shape);
  429. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  430.  
  431. const int geom_type = ShapeToGeometry(shape);
  432.  
  433. const int *dof_map = fec->GetDofMap(geom_type);
  434. for (int elem = 0; elem < EG.nElem; elem++)
  435. {
  436. fes->GetElementDofs(elem, dofs);
  437. const mfem::FiniteElement *fe = fes->GetFE(elem);
  438. const int ndof = fe->GetDof();
  439. for (int i = 0; i < ndof; i++) {
  440. for (int vd = 0; vd < dim; vd++) {
  441. (*Nodes)(dofs[dof_map[i]]*dim + vd) = xflow_mesh.Coord[0][EG.Node[elem][i] * dim + vd];
  442. }
  443. }
  444. }
  445. }
  446. }
  447.  
  448. int main(int argc, char *argv[])
  449. {
  450. int ierr;
  451. xf_All *All;
  452. const char *xf_mesh_file = "NULL";
  453. const char *xf_data_file = "NULL";
  454. const char *xf_xfa_file = "NULL";
  455. const char *convert_list_char = "";
  456. bool write = false;
  457. bool plot = true;
  458.  
  459. /// GLVis options
  460. char vishost[] = "localhost";
  461. int visport = 19916;
  462.  
  463. mfem::OptionsParser args(argc, argv);
  464. args.AddOption(&xf_mesh_file, "-m", "--mesh",
  465. "Mesh file to use.");
  466. args.AddOption(&xf_data_file, "-d", "--data",
  467. "Data file to use.");
  468. args.AddOption(&xf_xfa_file, "-x", "--xfa",
  469. "Xfa file to use.");
  470. args.AddOption(&convert_list_char, "-c", "--convert",
  471. "Comma-separated list of data names to convert.");
  472. args.AddOption(&write, "-w", "--write", "-no-w", "--no-write",
  473. "Enable or disable output writing.");
  474. args.AddOption(&plot, "-p", "--plot", "-no-p", "--no-plot",
  475. "Enable or disable plotting.");
  476. args.Parse();
  477. if (!args.Good())
  478. {
  479. args.PrintUsage(std::cout);
  480. return 1;
  481. }
  482. args.PrintOptions(std::cout);
  483.  
  484. /* Create .xfa structure */
  485. xf_Call(xf_CreateAll(&All, xfe_False));
  486.  
  487. if (strcmp(xf_mesh_file, "NULL"))
  488. {
  489. // Mesh file passed
  490. std::cout << "Using mesh " << xf_mesh_file << std::endl;
  491. xf_Call(xf_ReadGriFile(xf_mesh_file, NULL, All->Mesh));
  492. }
  493. else if (strcmp(xf_xfa_file, "NULL"))
  494. {
  495. // xfa file passed
  496. std::cout << "Using xfa " << xf_xfa_file << std::endl;
  497. xf_Call(xf_ReadAllBinary(xf_xfa_file, All));
  498. if (!strcmp(xf_data_file, "NULL"))
  499. {
  500. std::cout << "with " << xf_xfa_file;
  501. ierr = xf_Error(xf_ReadAllBinary(xf_xfa_file, All));
  502. if (ierr != xf_OK) throw std::runtime_error("An error occured");
  503. }
  504. }
  505.  
  506. if (strcmp(xf_data_file, "NULL"))
  507. {
  508. // Additional data file passed
  509. std::cout << "Using data file " << xf_data_file << std::endl;
  510.  
  511. xf_DataSet *DataSet;
  512. xf_Call(xf_CreateDataSet(&DataSet));
  513. xf_Call(xf_ReadDataSetBinary(All->Mesh, NULL, xf_data_file, DataSet));
  514. xf_Call(xf_DataSetMerge(DataSet, All->DataSet));
  515. xf_Call(xf_DestroyDataSet(DataSet));
  516. }
  517.  
  518. std::cout << "Converting mesh" << std::flush;
  519.  
  520. // --- Convert mesh ---
  521. XFMesh mesh(*All->Mesh);
  522.  
  523. std::cout << " ... done" << std::endl;
  524.  
  525. std::cout << "Reading data" << std::flush;
  526.  
  527. std::string convert_list(convert_list_char);
  528. int num_converted = 0;
  529. std::vector<mfem::GridFunction> gf_list;
  530. std::vector<std::string> gf_names;
  531. for (xf_Data *D = All->DataSet->Head; D != NULL; D = D->Next)
  532. {
  533. std::string data_title(D->Title);
  534. const std::size_t pos = convert_list.find(data_title);
  535. if (pos == std::string::npos) continue;
  536. std::cout << "Converting " << data_title << std::endl;
  537. if (D->Type == xfe_Vector)
  538. {
  539. xf_Vector *V = (xf_Vector *) D->Data;
  540. if (V->Linkage == xfe_LinkageGlobElem)
  541. {
  542. gf_list.emplace_back(convertXFVector(All->Mesh, &mesh, V));
  543. gf_names.emplace_back(std::string(D->Title));
  544. num_converted++;
  545. }
  546. }
  547. else if (D->Type == xfe_VectorGroup)
  548. {
  549. xf_VectorGroup *VG = (xf_VectorGroup *) D->Data;
  550. for (int i = 0; i < VG->nVector; i++)
  551. {
  552. if (VG->Vector[i]->Linkage == xfe_LinkageGlobElem)
  553. {
  554. gf_list.emplace_back(convertXFVector(All->Mesh, &mesh, VG->Vector[i]));
  555. gf_names.emplace_back(std::string(D->Title) + "_Vector" + std::to_string(i));
  556. num_converted++;
  557. }
  558. }
  559. }
  560. else
  561. {
  562. mfem::mfem_error("Type not supported");
  563. }
  564. }
  565.  
  566. std::cout << " ... done - number converted = " << num_converted << std::endl;
  567.  
  568. if (write)
  569. {
  570. // Save mesh
  571. std::ofstream ofs("xflow.mesh");
  572. ofs.precision(8);
  573. mesh.Print(ofs);
  574.  
  575. // Save gridfunctions
  576. for (int i = 0; i < gf_list.size(); i++)
  577. {
  578. std::stringstream ss;
  579. ss << gf_names[i] << ".gf";
  580. std::ofstream ofs(ss.str());
  581. ofs.precision(8);
  582. gf_list[i].Save(ofs);
  583. }
  584. }
  585.  
  586. if (plot)
  587. {
  588. if (gf_list.size() == 0)
  589. {
  590. // Plot only the mesh
  591. mfem::socketstream sout(vishost, visport);
  592. sout.precision(8);
  593. sout << "mesh\n" << mesh << std::flush;
  594. }
  595. else
  596. {
  597. // Loop over gridfunctions
  598. int Wx = 0, Wy = 0; // window position
  599. const int Ww = 350, Wh = 350; // window size
  600. int offx = Ww+10; // window offsets
  601. for (int i = 0; i < gf_list.size(); i++)
  602. {
  603. mfem::socketstream sout(vishost, visport);
  604. if (gf_list[i].VectorDim() == 2)
  605. {
  606. sout << "solution\n" << mesh << gf_list[i] << std::flush;
  607. sout << "window_title '" << gf_names[i] << "'\n"
  608. << "window_geometry "
  609. << Wx << " " << Wy << " " << Ww << " " << Wh << "\n" << std::flush;
  610. }
  611. else
  612. {
  613. std::cout << "WARNING: Skipping " << gf_names[i] << " because it has more than one vector output. Use -write and plot manually with GLVis using the -gc option." << std::endl;
  614. }
  615. }
  616. }
  617. }
  618.  
  619. /* Destroy .xfa structure */
  620. xf_Call(xf_DestroyAll(All));
  621.  
  622. return 0;
  623. }
Add Comment
Please, Sign In to add comment