GLVis  v4.2
Accurate and flexible finite element visualization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
stream_reader.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-443271.
4 //
5 // This file is part of the GLVis visualization tool and library. For more
6 // information and source code availability see https://glvis.org.
7 //
8 // GLVis is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "stream_reader.hpp"
13 #include "visual.hpp"
14 
15 #include <cstdlib>
16 
17 using namespace std;
18 using namespace mfem;
19 
21 {
22  if (mesh->Dimension() != 1 || mesh->SpaceDimension() != 1)
23  {
24  return;
25  }
26 
27  // find xmin and xmax over the vertices of the 1D mesh
28  double xmin = numeric_limits<double>::infinity();
29  double xmax = -xmin;
30  for (int i = 0; i < mesh->GetNV(); i++)
31  {
32  const double x = mesh->GetVertex(i)[0];
33  if (x < xmin)
34  {
35  xmin = x;
36  }
37  if (x > xmax)
38  {
39  xmax = x;
40  }
41  }
42 
43  Mesh *mesh2d = Extrude1D(mesh.get(), 1, 0.1*(xmax - xmin));
44 
45  if (grid_f)
46  {
47  GridFunction *grid_f_2d =
48  Extrude1DGridFunction(mesh.get(), mesh2d, grid_f.get(), 1);
49 
50  grid_f.reset(grid_f_2d);
51  }
52  else if (sol.Size() == mesh->GetNV())
53  {
54  Vector sol2d(mesh2d->GetNV());
55  for (int i = 0; i < mesh->GetNV(); i++)
56  {
57  sol2d(2*i+0) = sol2d(2*i+1) = sol(i);
58  }
59  sol = sol2d;
60  }
61 
62  mesh.reset(mesh2d);
63 }
64 
65 
67 {
68  if (1) // checkerboard solution
69  {
70  FiniteElementCollection *cfec;
71  if (mesh->Dimension() == 1)
72  {
73  cfec = new L2_FECollection(0, 1);
74  }
75  else if (mesh->Dimension() == 2)
76  {
77  cfec = new Const2DFECollection;
78  }
79  else
80  {
81  cfec = new Const3DFECollection;
82  }
83  FiniteElementSpace *cfes = new FiniteElementSpace(mesh.get(), cfec);
84  grid_f.reset(new GridFunction(cfes));
85  grid_f->MakeOwner(cfec);
86  {
87  Array<int> coloring;
88  srand(time(0));
89  double a = double(rand()) / (double(RAND_MAX) + 1.);
90  int el0 = (int)floor(a * mesh->GetNE());
91  cout << "Generating coloring starting with element " << el0+1
92  << " / " << mesh->GetNE() << endl;
93  mesh->GetElementColoring(coloring, el0);
94  for (int i = 0; i < coloring.Size(); i++)
95  {
96  (*grid_f)(i) = coloring[i];
97  }
98  cout << "Number of colors: " << grid_f->Max() + 1 << endl;
99  }
100  grid_f->GetNodalValues(sol);
101  is_gf = 1;
102  if (save_coloring)
103  {
104  const char col_fname[] = "GLVis_coloring.gf";
105  ofstream fgrid(col_fname);
106  cout << "Saving the coloring function -> " << flush;
107  grid_f->Save(fgrid);
108  cout << col_fname << endl;
109  }
110  }
111  else // zero solution
112  {
113  sol.SetSize (mesh -> GetNV());
114  sol = 0.0;
115  }
116 }
117 
118 
119 // Read the content of an input stream (e.g. from socket/file)
120 int StreamState::ReadStream(istream &is, const string &data_type)
121 {
122  // 0 - scalar data, 1 - vector data, 2 - mesh only, (-1) - unknown
123  int field_type = 0;
124  keys.clear();
125  if (data_type == "fem2d_data")
126  {
127  mesh.reset(new Mesh(is, 0, 0, fix_elem_orient));
128  sol.Load(is, mesh->GetNV());
129  }
130  else if (data_type == "vfem2d_data" || data_type == "vfem2d_data_keys")
131  {
132  field_type = 1;
133  mesh.reset(new Mesh(is, 0, 0, fix_elem_orient));
134  solu.Load(is, mesh->GetNV());
135  solv.Load(is, mesh->GetNV());
136  if (data_type == "vfem2d_data_keys")
137  {
138  is >> keys;
139  }
140  }
141  else if (data_type == "fem3d_data")
142  {
143  mesh.reset(new Mesh(is, 0, 0, fix_elem_orient));
144  sol.Load(is, mesh->GetNV());
145  }
146  else if (data_type == "vfem3d_data" || data_type == "vfem3d_data_keys")
147  {
148  field_type = 1;
149  mesh.reset(new Mesh(is, 0, 0, fix_elem_orient));
150  solu.Load(is, mesh->GetNV());
151  solv.Load(is, mesh->GetNV());
152  solw.Load(is, mesh->GetNV());
153  if (data_type == "vfem3d_data_keys")
154  {
155  is >> keys;
156  }
157  }
158  else if (data_type == "fem2d_gf_data" || data_type == "fem2d_gf_data_keys")
159  {
160  mesh.reset(new Mesh(is, 1, 0, fix_elem_orient));
161  grid_f.reset(new GridFunction(mesh.get(), is));
162  if (data_type == "fem2d_gf_data_keys")
163  {
164  is >> keys;
165  }
166  }
167  else if (data_type == "vfem2d_gf_data" || data_type == "vfem2d_gf_data_keys")
168  {
169  field_type = 1;
170  mesh.reset(new Mesh(is, 1, 0, fix_elem_orient));
171  grid_f.reset(new GridFunction(mesh.get(), is));
172  if (data_type == "vfem2d_gf_data_keys")
173  {
174  is >> keys;
175  }
176  }
177  else if (data_type == "fem3d_gf_data" || data_type == "fem3d_gf_data_keys")
178  {
179  mesh.reset(new Mesh(is, 1, 0, fix_elem_orient));
180  grid_f.reset(new GridFunction(mesh.get(), is));
181  if (data_type == "fem3d_gf_data_keys")
182  {
183  is >> keys;
184  }
185  }
186  else if (data_type == "vfem3d_gf_data" || data_type == "vfem3d_gf_data_keys")
187  {
188  field_type = 1;
189  mesh.reset(new Mesh(is, 1, 0, fix_elem_orient));
190  grid_f.reset(new GridFunction(mesh.get(), is));
191  if (data_type == "vfem3d_gf_data_keys")
192  {
193  is >> keys;
194  }
195  }
196  else if (data_type == "solution")
197  {
198  mesh.reset(new Mesh(is, 1, 0, fix_elem_orient));
199  grid_f.reset(new GridFunction(mesh.get(), is));
200  field_type = (grid_f->VectorDim() == 1) ? 0 : 1;
201  }
202  else if (data_type == "mesh")
203  {
204  mesh.reset(new Mesh(is, 1, 0, fix_elem_orient));
205  SetMeshSolution();
206  field_type = 2;
207  }
208  else if (data_type == "raw_scalar_2d")
209  {
210  Array<Array<double> *> vertices;
211  Array<Array<int> *> elements;
212  Array<int> elem_types;
213  string ident;
214  int num_patches, num_vert, num_elem, n;
215  is >> ws >> ident; // 'patches'
216  is >> num_patches;
217  // cout << ident << ' ' << num_patches << endl;
218  vertices.SetSize(num_patches);
219  vertices = NULL;
220  elements.SetSize(num_patches);
221  elements = NULL;
222  elem_types.SetSize(num_patches);
223  elem_types = 0;
224  int tot_num_vert = 0;
225  int tot_num_elem = 0;
226  int mesh_type = 0;
227  for (int i = 0; i < num_patches; i++)
228  {
229  is >> ws >> ident; // 'vertices'
230  is >> num_vert;
231  // cout << '\n' << ident << ' ' << num_vert << endl;
232  // read vertices in the format: x y z nx ny nz
233  vertices[i] = new Array<double>(6*num_vert);
234  Array<double> &verts = *vertices[i];
235  for (int j = 0; j < verts.Size(); j++)
236  {
237  is >> verts[j];
238  }
239 
240  is >> ws >> ident; // 'triangles' or 'quads'
241  if (ident == "triangles")
242  {
243  n = 3, mesh_type |= 1;
244  }
245  else
246  {
247  n = 4, mesh_type |= 2;
248  }
249  elem_types[i] = n;
250  is >> num_elem;
251  // cout << ident << ' ' << num_elem << endl;
252  elements[i] = new Array<int>(n*num_elem);
253  Array<int> &elems = *elements[i];
254  for (int j = 0; j < elems.Size(); j++)
255  {
256  is >> elems[j];
257  elems[j] += tot_num_vert;
258  }
259  tot_num_vert += num_vert;
260  tot_num_elem += num_elem;
261  }
262 
263  mesh.reset(new Mesh(2, tot_num_vert, tot_num_elem, 0));
264  sol.SetSize(tot_num_vert);
265  normals.SetSize(3*tot_num_vert);
266 
267  int v_off = 0;
268  for (int i = 0; i < num_patches; i++)
269  {
270  Array<double> &verts = *vertices[i];
271  num_vert = verts.Size()/6;
272  for (int j = 0; j < num_vert; j++)
273  {
274  mesh->AddVertex(&verts[6*j]);
275  sol(v_off) = verts[6*j+2];
276  normals(3*v_off+0) = verts[6*j+3];
277  normals(3*v_off+1) = verts[6*j+4];
278  normals(3*v_off+2) = verts[6*j+5];
279  v_off++;
280  }
281 
282  n = elem_types[i];
283  Array<int> &elems = *elements[i];
284  num_elem = elems.Size()/n;
285  // int attr = 1;
286  int attr = i + 1;
287  if (n == 3)
288  for (int j = 0; j < num_elem; j++)
289  {
290  mesh->AddTriangle(&elems[3*j], attr);
291  }
292  else
293  for (int j = 0; j < num_elem; j++)
294  {
295  mesh->AddQuad(&elems[4*j], attr);
296  }
297  }
298 
299  if (mesh_type == 1)
300  {
301  mesh->FinalizeTriMesh(1, 0, fix_elem_orient);
302  }
303  else if (mesh_type == 2)
304  {
305  mesh->FinalizeQuadMesh(1, 0, fix_elem_orient);
306  }
307  else
308  {
309  mfem_error("Input data contains mixture of triangles and quads!");
310  }
311 
312  mesh->GenerateBoundaryElements();
313 
314  for (int i = num_patches; i > 0; )
315  {
316  i--;
317  delete elements[i];
318  delete vertices[i];
319  }
320 
321  field_type = 0;
322  }
323  else
324  {
325  field_type = -1;
326  cerr << "Unknown data format" << endl;
327  cerr << data_type << endl;
328  }
329 
330  if (field_type >= 0 && field_type <= 2)
331  {
332  Extrude1DMeshAndSolution();
333  }
334 
335  return field_type;
336 }
337 
338 // Replace a given VectorFiniteElement-based grid function (e.g. from a Nedelec
339 // or Raviart-Thomas space) with a discontinuous piece-wise polynomial Cartesian
340 // product vector grid function of the same order.
341 std::unique_ptr<GridFunction>
342 ProjectVectorFEGridFunction(std::unique_ptr<GridFunction> gf)
343 {
344  if ((gf->VectorDim() == 3) && (gf->FESpace()->GetVDim() == 1))
345  {
346  int p = gf->FESpace()->GetOrder(0);
347  cout << "Switching to order " << p
348  << " discontinuous vector grid function..." << endl;
349  int dim = gf->FESpace()->GetMesh()->Dimension();
350  FiniteElementCollection *d_fec =
351  (p == 1 && dim == 3) ?
352  (FiniteElementCollection*)new LinearDiscont3DFECollection :
353  (FiniteElementCollection*)new L2_FECollection(p, dim, 1);
354  FiniteElementSpace *d_fespace =
355  new FiniteElementSpace(gf->FESpace()->GetMesh(), d_fec, 3);
356  GridFunction *d_gf = new GridFunction(d_fespace);
357  d_gf->MakeOwner(d_fec);
358  gf->ProjectVectorFieldOn(*d_gf);
359  gf.reset(d_gf);
360  }
361  return gf;
362 }
363 
366 {
367  if (new_state.mesh->SpaceDimension() == mesh->SpaceDimension() &&
368  new_state.grid_f->VectorDim() == grid_f->VectorDim())
369  {
370  std::unique_ptr<mfem::Mesh> new_m = std::move(new_state.mesh);
371  std::unique_ptr<mfem::GridFunction> new_g = std::move(new_state.grid_f);
372  if (new_m->SpaceDimension() == 2)
373  {
374  if (new_g->VectorDim() == 1)
375  {
377  dynamic_cast<VisualizationSceneSolution *>(vs);
378  new_g->GetNodalValues(sol);
379  vss->NewMeshAndSolution(new_m.get(), &sol, new_g.get());
380  }
381  else
382  {
384  dynamic_cast<VisualizationSceneVector *>(vs);
385  vsv->NewMeshAndSolution(*new_g);
386  }
387  }
388  else
389  {
390  if (new_g->VectorDim() == 1)
391  {
393  dynamic_cast<VisualizationSceneSolution3d *>(vs);
394  new_g->GetNodalValues(sol);
395  vss->NewMeshAndSolution(new_m.get(), &sol, new_g.get());
396  }
397  else
398  {
399  new_g = ProjectVectorFEGridFunction(std::move(new_g));
400 
402  dynamic_cast<VisualizationSceneVector3d *>(vs);
403  vss->NewMeshAndSolution(new_m.get(), new_g.get());
404  }
405  }
406  grid_f = std::move(new_g);
407  mesh = std::move(new_m);
408  return true;
409  }
410  else
411  {
412  return false;
413  }
414 }
std::unique_ptr< GridFunction > ProjectVectorFEGridFunction(std::unique_ptr< GridFunction > gf)
void Extrude1DMeshAndSolution()
Helper function for visualizing 1D data.
std::unique_ptr< mfem::GridFunction > grid_f
thread_local VisualizationSceneScalarData * vs
Definition: glvis.cpp:67
void SetMeshSolution()
Set a (checkerboard) solution when only the mesh is given.
void NewMeshAndSolution(Mesh *new_m, Vector *new_sol, GridFunction *new_u=NULL)
Definition: vssolution.cpp:575
bool SetNewMeshAndSolution(StreamState new_state, VisualizationScene *vs)
void NewMeshAndSolution(GridFunction &vgf)
Definition: vsvector.cpp:406
std::unique_ptr< mfem::Mesh > mesh
void NewMeshAndSolution(Mesh *new_m, GridFunction *new_v)
Definition: vsvector3d.cpp:453
int ReadStream(std::istream &is, const std::string &data_type)
void NewMeshAndSolution(Mesh *new_m, Vector *new_sol, GridFunction *new_u=NULL)