MFEM  v4.2.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
datacollection.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2020, 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-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM 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 "fem.hpp"
13 #include "../mesh/nurbs.hpp"
14 #include "../general/binaryio.hpp"
15 #include "../general/text.hpp"
16 #include "picojson.h"
17 
18 #include <cerrno> // errno
19 #include <sstream>
20 
21 #ifndef _WIN32
22 #include <sys/stat.h> // mkdir
23 #else
24 #include <direct.h> // _mkdir
25 #define mkdir(dir, mode) _mkdir(dir)
26 #endif
27 
28 namespace mfem
29 {
30 
31 // static method
32 int DataCollection::create_directory(const std::string &dir_name,
33  const Mesh *mesh, int myid)
34 {
35  // create directories recursively
36  const char path_delim = '/';
37  std::string::size_type pos = 0;
38  int err;
39 #ifdef MFEM_USE_MPI
40  const ParMesh *pmesh = dynamic_cast<const ParMesh*>(mesh);
41 #endif
42 
43  do
44  {
45  pos = dir_name.find(path_delim, pos+1);
46  std::string subdir = dir_name.substr(0, pos);
47 
48 #ifndef MFEM_USE_MPI
49  err = mkdir(subdir.c_str(), 0777);
50  err = (err && (errno != EEXIST)) ? 1 : 0;
51 #else
52  if (myid == 0 || pmesh == NULL)
53  {
54  err = mkdir(subdir.c_str(), 0777);
55  err = (err && (errno != EEXIST)) ? 1 : 0;
56  }
57 #endif
58  }
59  while ( pos != std::string::npos );
60 
61 #ifdef MFEM_USE_MPI
62  if (pmesh)
63  {
64  MPI_Bcast(&err, 1, MPI_INT, 0, pmesh->GetComm());
65  }
66 #endif
67 
68  return err;
69 }
70 
71 // class DataCollection implementation
72 
73 DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
74 {
75  std::string::size_type pos = collection_name.find_last_of('/');
76  if (pos == std::string::npos)
77  {
78  name = collection_name;
79  // leave prefix_path empty
80  }
81  else
82  {
83  prefix_path = collection_name.substr(0, pos+1);
84  name = collection_name.substr(pos+1);
85  }
86  mesh = mesh_;
87  myid = 0;
88  num_procs = 1;
89  serial = true;
90  appendRankToFileName = false;
91 
92 #ifdef MFEM_USE_MPI
93  m_comm = MPI_COMM_NULL;
94  ParMesh *par_mesh = dynamic_cast<ParMesh*>(mesh);
95  if (par_mesh)
96  {
97  myid = par_mesh->GetMyRank();
98  num_procs = par_mesh->GetNRanks();
99  m_comm = par_mesh->GetComm();
100  serial = false;
101  appendRankToFileName = true;
102  }
103 #endif
104  own_data = false;
105  cycle = -1;
106  time = 0.0;
107  time_step = 0.0;
110  format = SERIAL_FORMAT; // use serial mesh format
111  compression = false;
112  error = NO_ERROR;
113 }
114 
116 {
117  if (own_data && new_mesh != mesh) { delete mesh; }
118  mesh = new_mesh;
119  myid = 0;
120  num_procs = 1;
121  serial = true;
122  appendRankToFileName = false;
123 
124 #ifdef MFEM_USE_MPI
125  m_comm = MPI_COMM_NULL;
126  ParMesh *par_mesh = dynamic_cast<ParMesh*>(mesh);
127  if (par_mesh)
128  {
129  myid = par_mesh->GetMyRank();
130  num_procs = par_mesh->GetNRanks();
131  m_comm = par_mesh->GetComm();
132  serial = false;
133  appendRankToFileName = true;
134  }
135 #endif
136 }
137 
138 #ifdef MFEM_USE_MPI
139 void DataCollection::SetMesh(MPI_Comm comm, Mesh *new_mesh)
140 {
141  // This seems to be the cleanest way to accomplish this
142  // and avoid duplicating fine grained details:
143 
144  SetMesh(new_mesh);
145 
146  m_comm = comm;
147  MPI_Comm_rank(comm, &myid);
148  MPI_Comm_size(comm, &num_procs);
149 }
150 #endif
151 
153 {
154  switch (fmt)
155  {
156  case SERIAL_FORMAT: break;
157 #ifdef MFEM_USE_MPI
158  case PARALLEL_FORMAT: break;
159 #endif
160  default: MFEM_ABORT("unknown format: " << fmt);
161  }
162  format = fmt;
163 }
164 
166 {
167  compression = comp;
168 #ifndef MFEM_USE_ZLIB
169  MFEM_VERIFY(!compression, "ZLib not enabled in MFEM build.");
170 #endif
171 }
172 
173 void DataCollection::SetPrefixPath(const std::string& prefix)
174 {
175  if (!prefix.empty())
176  {
177  prefix_path = prefix;
178  if (!prefix_path.empty() && prefix_path[prefix_path.size()-1] != '/')
179  {
180  prefix_path += '/';
181  }
182  }
183  else
184  {
185  prefix_path.clear();
186  }
187 }
188 
189 void DataCollection::Load(int cycle)
190 {
191  MFEM_ABORT("this method is not implemented");
192 }
193 
195 {
196  SaveMesh();
197 
198  if (error) { return; }
199 
200  for (FieldMapIterator it = field_map.begin(); it != field_map.end(); ++it)
201  {
202  SaveOneField(it);
203  // Even if there is an error, try saving the other fields
204  }
205 
206  for (QFieldMapIterator it = q_field_map.begin(); it != q_field_map.end();
207  ++it)
208  {
209  SaveOneQField(it);
210  }
211 }
212 
214 {
215  int err;
216 
217  std::string dir_name = prefix_path + name;
218  if (cycle != -1)
219  {
220  dir_name += "_" + to_padded_string(cycle, pad_digits_cycle);
221  }
222  err = create_directory(dir_name, mesh, myid);
223  if (err)
224  {
225  error = WRITE_ERROR;
226  MFEM_WARNING("Error creating directory: " << dir_name);
227  return; // do not even try to write the mesh
228  }
229 
230  std::string mesh_name = GetMeshFileName();
231  mfem::ofgzstream mesh_file(mesh_name, compression);
232  mesh_file.precision(precision);
233 #ifdef MFEM_USE_MPI
234  const ParMesh *pmesh = dynamic_cast<const ParMesh*>(mesh);
235  if (pmesh && format == PARALLEL_FORMAT)
236  {
237  pmesh->ParPrint(mesh_file);
238  }
239  else
240 #endif
241  {
242  mesh->Print(mesh_file);
243  }
244  if (!mesh_file)
245  {
246  error = WRITE_ERROR;
247  MFEM_WARNING("Error writing mesh to file: " << mesh_name);
248  }
249 }
250 
252 {
253  return (serial || format == SERIAL_FORMAT) ? "mesh" : "pmesh";
254 }
255 
257 {
259 }
260 
261 std::string DataCollection::GetFieldFileName(const std::string &field_name)
262 const
263 {
264  std::string dir_name = prefix_path + name;
265  if (cycle != -1)
266  {
267  dir_name += "_" + to_padded_string(cycle, pad_digits_cycle);
268  }
269  std::string file_name = dir_name + "/" + field_name;
271  {
272  file_name += "." + to_padded_string(myid, pad_digits_rank);
273  }
274  return file_name;
275 }
276 
278 {
279  mfem::ofgzstream field_file(GetFieldFileName(it->first), compression);
280 
281  field_file.precision(precision);
282  (it->second)->Save(field_file);
283  if (!field_file)
284  {
285  error = WRITE_ERROR;
286  MFEM_WARNING("Error writing field to file: " << it->first);
287  }
288 }
289 
291 {
292  mfem::ofgzstream q_field_file(GetFieldFileName(it->first), compression);
293 
294  q_field_file.precision(precision);
295  (it->second)->Save(q_field_file);
296  if (!q_field_file)
297  {
298  error = WRITE_ERROR;
299  MFEM_WARNING("Error writing q-field to file: " << it->first);
300  }
301 }
302 
303 void DataCollection::SaveField(const std::string &field_name)
304 {
305  FieldMapIterator it = field_map.find(field_name);
306  if (it != field_map.end())
307  {
308  SaveOneField(it);
309  }
310 }
311 
312 void DataCollection::SaveQField(const std::string &q_field_name)
313 {
314  QFieldMapIterator it = q_field_map.find(q_field_name);
315  if (it != q_field_map.end())
316  {
317  SaveOneQField(it);
318  }
319 }
320 
322 {
323  if (own_data) { delete mesh; }
324  mesh = NULL;
325 
328  own_data = false;
329 }
330 
332 {
333  DeleteData();
334  field_map.clear();
335  q_field_map.clear();
336 }
337 
339 {
340  DeleteData();
341 }
342 
343 
344 // class VisItDataCollection implementation
345 
347 {
348  if (mesh)
349  {
351  topo_dim = mesh->Dimension();
352  if (mesh->NURBSext)
353  {
356  }
357  }
358  else
359  {
360  spatial_dim = 0;
361  topo_dim = 0;
362  }
363 }
364 
365 VisItDataCollection::VisItDataCollection(const std::string& collection_name,
366  Mesh *mesh)
367  : DataCollection(collection_name, mesh)
368 {
369  appendRankToFileName = true; // always include rank in file names
370  cycle = 0; // always include cycle in directory names
371 
374 
375  UpdateMeshInfo();
376 }
377 
378 #ifdef MFEM_USE_MPI
380  const std::string& collection_name,
381  Mesh *mesh)
382  : DataCollection(collection_name, mesh)
383 {
384  m_comm = comm;
385  MPI_Comm_rank(comm, &myid);
386  MPI_Comm_size(comm, &num_procs);
387  appendRankToFileName = true; // always include rank in file names
388  cycle = 0; // always include cycle in directory names
389 
392 
393  UpdateMeshInfo();
394 }
395 #endif
396 
398 {
399  DataCollection::SetMesh(new_mesh);
400  appendRankToFileName = true;
401  UpdateMeshInfo();
402 }
403 
404 #ifdef MFEM_USE_MPI
405 void VisItDataCollection::SetMesh(MPI_Comm comm, Mesh *new_mesh)
406 {
407  // use VisItDataCollection's custom SetMesh, then set MPI info
408  SetMesh(new_mesh);
409  m_comm = comm;
410  MPI_Comm_rank(comm, &myid);
411  MPI_Comm_size(comm, &num_procs);
412 }
413 #endif
414 
415 void VisItDataCollection::RegisterField(const std::string& name,
416  GridFunction *gf)
417 {
418  int LOD = 1;
419  if (gf->FESpace()->GetNURBSext())
420  {
421  LOD = gf->FESpace()->GetNURBSext()->GetOrder();
422  }
423  else
424  {
425  for (int e=0; e<gf->FESpace()->GetNE(); e++)
426  {
427  LOD = std::max(LOD,gf->FESpace()->GetFE(e)->GetOrder());
428  }
429  }
430 
432  field_info_map[name] = VisItFieldInfo("nodes", gf->VectorDim(), LOD);
433  visit_levels_of_detail = std::max(visit_levels_of_detail, LOD);
434 }
435 
436 void VisItDataCollection::RegisterQField(const std::string& name,
437  QuadratureFunction *qf)
438 {
439  int LOD = -1;
440  Mesh *mesh = qf->GetSpace()->GetMesh();
441  for (int e=0; e<qf->GetSpace()->GetNE(); e++)
442  {
444  mesh->GetElementBaseGeometry(e),
445  qf->GetElementIntRule(e).GetNPoints());
446 
447  LOD = std::max(LOD,locLOD);
448  }
449 
451  field_info_map[name] = VisItFieldInfo("elements", 1, LOD);
453 }
454 
455 void VisItDataCollection::SetLevelsOfDetail(int levels_of_detail)
456 {
457  visit_levels_of_detail = levels_of_detail;
458 }
459 
460 void VisItDataCollection::SetMaxLevelsOfDetail(int max_levels_of_detail)
461 {
462  visit_max_levels_of_detail = max_levels_of_detail;
463 }
464 
466 {
467  field_info_map.clear();
469 }
470 
472 {
474  SaveRootFile();
475 }
476 
478 {
479  if (myid != 0) { return; }
480 
481  std::string root_name = prefix_path + name + "_" +
483  ".mfem_root";
484  std::ofstream root_file(root_name.c_str());
485  root_file << GetVisItRootString();
486  if (!root_file)
487  {
488  error = WRITE_ERROR;
489  MFEM_WARNING("Error writing VisIt root file: " << root_name);
490  }
491 }
492 
494 {
495  DeleteAll();
496  time_step = 0.0;
497  error = NO_ERROR;
498  cycle = cycle_;
499  std::string root_name = prefix_path + name + "_" +
501  ".mfem_root";
502  LoadVisItRootFile(root_name);
503  if (format != SERIAL_FORMAT || num_procs > 1)
504  {
505 #ifndef MFEM_USE_MPI
506  MFEM_WARNING("Cannot load parallel VisIt root file in serial.");
507  error = READ_ERROR;
508 #else
509  if (m_comm == MPI_COMM_NULL)
510  {
511  MFEM_WARNING("Cannot load parallel VisIt root file without MPI"
512  " communicator");
513  error = READ_ERROR;
514  }
515  else
516  {
517  // num_procs was read from the root file, check for consistency with
518  // the associated MPI_Comm, m_comm:
519  int comm_size;
520  MPI_Comm_size(m_comm, &comm_size);
521  if (comm_size != num_procs)
522  {
523  MFEM_WARNING("Processor number mismatch: VisIt root file: "
524  << num_procs << ", MPI_comm: " << comm_size);
525  error = READ_ERROR;
526  }
527  else
528  {
529  // myid was set when setting m_comm
530  }
531  }
532 #endif
533  }
534  if (!error)
535  {
536  LoadMesh(); // sets own_data to true, when there is no error
537  }
538  if (!error)
539  {
540  LoadFields();
541  }
542  if (error)
543  {
544  DeleteAll();
545  }
546 }
547 
548 void VisItDataCollection::LoadVisItRootFile(const std::string& root_name)
549 {
550  std::ifstream root_file(root_name.c_str());
551  std::stringstream buffer;
552  buffer << root_file.rdbuf();
553  if (!buffer)
554  {
555  error = READ_ERROR;
556  MFEM_WARNING("Error reading the VisIt root file: " << root_name);
557  }
558  else
559  {
560  ParseVisItRootString(buffer.str());
561  }
562 }
563 
565 {
566  // GetMeshFileName() uses 'serial', so we need to set it in advance.
567  serial = (format == SERIAL_FORMAT);
568  std::string mesh_fname = GetMeshFileName();
569  named_ifgzstream file(mesh_fname);
570  // TODO: in parallel, check for errors on all processors
571  if (!file)
572  {
573  error = READ_ERROR;
574  MFEM_WARNING("Unable to open mesh file: " << mesh_fname);
575  return;
576  }
577  // TODO: 1) load parallel mesh on one processor
578  if (format == SERIAL_FORMAT)
579  {
580  mesh = new Mesh(file, 1, 0, false);
581  serial = true;
582  }
583  else
584  {
585 #ifdef MFEM_USE_MPI
586  mesh = new ParMesh(m_comm, file);
587  serial = false;
588 #else
589  error = READ_ERROR;
590  MFEM_WARNING("Reading parallel format in serial is not supported");
591  return;
592 #endif
593  }
595  topo_dim = mesh->Dimension();
596  own_data = true;
597 }
598 
600 {
601  std::string path_left = prefix_path + name + "_" +
603  std::string path_right = "." + to_padded_string(myid, pad_digits_rank);
604 
605  field_map.clear();
606  for (FieldInfoMapIterator it = field_info_map.begin();
607  it != field_info_map.end(); ++it)
608  {
609  std::string fname = path_left + it->first + path_right;
610  mfem::ifgzstream file(fname);
611  // TODO: in parallel, check for errors on all processors
612  if (!file)
613  {
614  error = READ_ERROR;
615  MFEM_WARNING("Unable to open field file: " << fname);
616  return;
617  }
618  // TODO: 1) load parallel GridFunction on one processor
619  if (serial)
620  {
621  if ((it->second).association == "nodes")
622  {
623  field_map.Register(it->first, new GridFunction(mesh, file), own_data);
624  }
625  else if ((it->second).association == "elements")
626  {
627  q_field_map.Register(it->first, new QuadratureFunction(mesh, file), own_data);
628  }
629  }
630  else
631  {
632 #ifdef MFEM_USE_MPI
633  if ((it->second).association == "nodes")
634  {
636  it->first,
637  new ParGridFunction(dynamic_cast<ParMesh*>(mesh), file), own_data);
638  }
639  else if ((it->second).association == "elements")
640  {
641  q_field_map.Register(it->first, new QuadratureFunction(mesh, file), own_data);
642  }
643 #else
644  error = READ_ERROR;
645  MFEM_WARNING("Reading parallel format in serial is not supported");
646  return;
647 #endif
648  }
649  }
650 }
651 
653 {
654  // Get the path string (relative to where the root file is, i.e. no prefix).
655  std::string path_str =
657 
658  // We have to build the json tree inside out to get all the values in there
659  picojson::object top, dsets, main, mesh, fields, field, mtags, ftags;
660 
661  // Build the mesh data
662  std::string file_ext_format = ".%0" + to_string(pad_digits_rank) + "d";
663  mtags["spatial_dim"] = picojson::value(to_string(spatial_dim));
664  mtags["topo_dim"] = picojson::value(to_string(topo_dim));
665  mtags["max_lods"] = picojson::value(to_string(visit_max_levels_of_detail));
666  mesh["path"] = picojson::value(path_str + GetMeshShortFileName() +
667  file_ext_format);
668  mesh["tags"] = picojson::value(mtags);
669  mesh["format"] = picojson::value(to_string(format));
670 
671  // Build the fields data entries
672  for (FieldInfoMapIterator it = field_info_map.begin();
673  it != field_info_map.end(); ++it)
674  {
675  ftags["assoc"] = picojson::value((it->second).association);
676  ftags["comps"] = picojson::value(to_string((it->second).num_components));
677  ftags["lod"] = picojson::value(to_string((it->second).lod));
678  field["path"] = picojson::value(path_str + it->first + file_ext_format);
679  field["tags"] = picojson::value(ftags);
680  fields[it->first] = picojson::value(field);
681  }
682 
683  main["cycle"] = picojson::value(double(cycle));
684  main["time"] = picojson::value(time);
685  main["time_step"] = picojson::value(time_step);
686  main["domains"] = picojson::value(double(num_procs));
687  main["mesh"] = picojson::value(mesh);
688  if (!field_info_map.empty())
689  {
690  main["fields"] = picojson::value(fields);
691  }
692 
693  dsets["main"] = picojson::value(main);
694  top["dsets"] = picojson::value(dsets);
695 
696  return picojson::value(top).serialize(true);
697 }
698 
699 void VisItDataCollection::ParseVisItRootString(const std::string& json)
700 {
701  picojson::value top, dsets, main, mesh, fields;
702  std::string parse_err = picojson::parse(top, json);
703  if (!parse_err.empty())
704  {
705  error = READ_ERROR;
706  MFEM_WARNING("Unable to parse VisIt root data.");
707  return;
708  }
709 
710  // Process "main"
711  dsets = top.get("dsets");
712  main = dsets.get("main");
713  cycle = int(main.get("cycle").get<double>());
714  time = main.get("time").get<double>();
715  if (main.contains("time_step"))
716  {
717  time_step = main.get("time_step").get<double>();
718  }
719  num_procs = int(main.get("domains").get<double>());
720  mesh = main.get("mesh");
721  fields = main.get("fields");
722 
723  // ... Process "mesh"
724 
725  // Set the DataCollection::name using the mesh path
726  std::string path = mesh.get("path").get<std::string>();
727  size_t right_sep = path.find('_');
728  if (right_sep == std::string::npos)
729  {
730  error = READ_ERROR;
731  MFEM_WARNING("Unable to parse VisIt root data.");
732  return;
733  }
734  name = path.substr(0, right_sep);
735 
736  if (mesh.contains("format"))
737  {
738  format = to_int(mesh.get("format").get<std::string>());
739  }
740  spatial_dim = to_int(mesh.get("tags").get("spatial_dim").get<std::string>());
741  topo_dim = to_int(mesh.get("tags").get("topo_dim").get<std::string>());
743  to_int(mesh.get("tags").get("max_lods").get<std::string>());
744 
745  // ... Process "fields"
746  field_info_map.clear();
747  if (fields.is<picojson::object>())
748  {
749  picojson::object fields_obj = fields.get<picojson::object>();
750  for (picojson::object::iterator it = fields_obj.begin();
751  it != fields_obj.end(); ++it)
752  {
753  picojson::value tags = it->second.get("tags");
754  field_info_map[it->first] =
755  VisItFieldInfo(tags.get("assoc").get<std::string>(),
756  to_int(tags.get("comps").get<std::string>()));
757  }
758  }
759 }
760 
762  collection_name,
763  Mesh *mesh_)
764  : DataCollection(collection_name, mesh_),
765  levels_of_detail(1),
766  pv_data_format(VTKFormat::BINARY),
767  high_order_output(false)
768 {
769 #ifdef MFEM_USE_ZLIB
770  compression = -1; // default zlib compression level, equivalent to 6
771 #else
772  compression = 0;
773 #endif
774 }
775 
776 void ParaViewDataCollection::SetLevelsOfDetail(int levels_of_detail_)
777 {
778  levels_of_detail = levels_of_detail_;
779 }
780 
782 {
783  MFEM_WARNING("ParaViewDataCollection::Load() is not implemented!");
784 }
785 
787 {
788  std::string out = "";
790  return out;
791 }
792 
794 {
795  std::string out = "Cycle" + to_padded_string(cycle,pad_digits_cycle);
796  return out;
797 }
798 
800 {
801  std::string out = GeneratePVTUPath();
802  return out;
803 }
804 
806 {
807  std::string out = GetCollectionName()+".pvd";
808  return out;
809 }
810 
812 {
813  std::string out = "data.pvtu";
814  return out;
815 }
816 
818 {
819  std::string out = "proc" + to_padded_string(myid,pad_digits_rank)+".vtu";
820  return out;
821 }
823 {
824  std::string out = "proc" + to_padded_string(crank,pad_digits_rank)+".vtu";
825  return out;
826 }
827 
829 {
830  // add a new collection to the PDV file
831 
832  // check if the directories are created
833  {
834  std::string path = GenerateCollectionPath()+"/"+GenerateVTUPath();
835  int err = create_directory(path, mesh, myid);
836  if (err)
837  {
838  error = WRITE_ERROR;
839  MFEM_WARNING("Error creating directory: " << path);
840  return; // do not even try to write the mesh
841  }
842  }
843  // the directory is created
844 
845  // create pvd file if needed
846  if (myid == 0 && !pvd_stream.is_open())
847  {
848  std::string dpath=GenerateCollectionPath();
849  std::string pvdname=dpath+"/"+GeneratePVDFileName();
850  pvd_stream.open(pvdname.c_str(),std::ios::out);
851  // initialize the file
852  pvd_stream << "<?xml version=\"1.0\"?>\n";
853  pvd_stream << "<VTKFile type=\"Collection\" version=\"0.1\"";
854  pvd_stream << " byte_order=\"" << VTKByteOrder() << "\">\n";
855  pvd_stream << "<Collection>" << std::endl;
856  }
857 
858  // define the vtu file
859  {
860  std::string fname = GenerateCollectionPath()+"/"+GenerateVTUPath()+"/"
862  std::fstream out(fname.c_str(), std::ios::out);
863  out.precision(precision);
864  SaveDataVTU(out,levels_of_detail);
865  out.close();
866  }
867 
868  // define the pvtu file only on process 0
869  if (myid==0)
870  {
871  std::string fname = GenerateCollectionPath()+"/"+GeneratePVTUPath()+"/"
873  std::fstream out(fname.c_str(), std::ios::out);
874 
875  out << "<?xml version=\"1.0\"?>\n";
876  out << "<VTKFile type=\"PUnstructuredGrid\"";
877  out << " version =\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
878  out << "<PUnstructuredGrid GhostLevel=\"0\">\n";
879 
880  out << "<PPoints>\n";
881  out << "\t<PDataArray type=\"" << GetDataTypeString() << "\" ";
882  out << " Name=\"Points\" NumberOfComponents=\"3\""
883  << " format=\"" << GetDataFormatString() << "\"/>\n";
884  out << "</PPoints>\n";
885 
886  out << "<PCells>\n";
887  out << "\t<PDataArray type=\"Int32\" ";
888  out << " Name=\"connectivity\" NumberOfComponents=\"1\""
889  << " format=\"" << GetDataFormatString() << "\"/>\n";
890  out << "\t<PDataArray type=\"Int32\" ";
891  out << " Name=\"offsets\" NumberOfComponents=\"1\""
892  << " format=\"" << GetDataFormatString() << "\"/>\n";
893  out << "\t<PDataArray type=\"UInt8\" ";
894  out << " Name=\"types\" NumberOfComponents=\"1\""
895  << " format=\"" << GetDataFormatString() << "\"/>\n";
896  out << "</PCells>\n";
897 
898  out << "<PPointData>\n";
899  for (FieldMapIterator it=field_map.begin(); it!=field_map.end(); ++it)
900  {
901  int vec_dim=it->second->VectorDim();
902  out << "<PDataArray type=\"" << GetDataTypeString()
903  << "\" Name=\"" << it->first
904  << "\" NumberOfComponents=\"" << vec_dim << "\" "
905  << "format=\"" << GetDataFormatString() << "\" />\n";
906  }
907  out << "</PPointData>\n";
908 
909  // CELL DATA
910  out << "<PCellData>\n";
911  out << "\t<PDataArray type=\"Int32\" Name=\"" << "attribute"
912  << "\" NumberOfComponents=\"1\""
913  << " format=\"" << GetDataFormatString() << "\"/>\n";
914  out << "</PCellData>\n";
915 
916  for (int ii=0; ii<num_procs; ii++)
917  {
918  // this one is generated without the path
919  std::string nfname=GenerateVTUFileName(ii);
920  out << "<Piece Source=\"" << nfname << "\"/>\n";
921  }
922  out << "</PUnstructuredGrid>\n";
923  out << "</VTKFile>\n";
924  out.close();
925 
926  fname = GeneratePVTUPath()+"/"+GeneratePVTUFileName();
927  // add the pvtu file to the pvd_stream
928  pvd_stream << "<DataSet timestep=\"" << GetTime(); // GetCycle();
929  pvd_stream << "\" group=\"\" part=\"" << 0 << "\" file=\"";
930  pvd_stream << fname << "\"/>\n";
931  std::fstream::pos_type pos = pvd_stream.tellp();
932  pvd_stream << "</Collection>\n";
933  pvd_stream << "</VTKFile>" << std::endl;
934  pvd_stream.seekp(pos);
935  }
936 }
937 
938 void ParaViewDataCollection::SaveDataVTU(std::ostream &out, int ref)
939 {
940  out << "<VTKFile type=\"UnstructuredGrid\"";
941  if (compression != 0)
942  {
943  out << " compressor=\"vtkZLibDataCompressor\"";
944  }
945  out << " version=\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
946  out << "<UnstructuredGrid>\n";
947  mesh->PrintVTU(out,ref,pv_data_format,high_order_output,compression);
948 
949  // dump out the grid functions as point data
950  out << "<PointData >\n";
951  // save the grid functions
952  // iterate over all grid functions
953  for (FieldMapIterator it=field_map.begin(); it!=field_map.end(); ++it)
954  {
955  SaveGFieldVTU(out,ref,it);
956  }
957  // iterate over all quadrature functions
958  // if the Quadrature functions are dumped as cell data
959  // the cycle should be moved before the grid functions
960  // and the PrintVTU CellData section should be open in the mesh dump
961  for (QFieldMapIterator it=q_field_map.begin(); it!=q_field_map.end(); ++it)
962  {
963  // save the quadrature functions
964  // this one is not implemented yet
965  SaveQFieldVTU(out,ref,it);
966  }
967  out << "</PointData>\n";
968  // close the mesh
969  out << "</Piece>\n"; // close the piece open in the PrintVTU method
970  out << "</UnstructuredGrid>\n";
971  out << "</VTKFile>" << std::endl;
972 }
973 
974 void ParaViewDataCollection::SaveQFieldVTU(std::ostream &out, int ref,
975  const QFieldMapIterator& it )
976 {
977  MFEM_WARNING("SaveQFieldVTU is not currently implemented - field name:"<<it->second);
978 }
979 
980 void ParaViewDataCollection::SaveGFieldVTU(std::ostream &out, int ref_,
981  const FieldMapIterator& it)
982 {
983  RefinedGeometry *RefG;
984  Vector val;
985  DenseMatrix vval, pmat;
986  std::vector<char> buf;
987  int vec_dim = it->second->VectorDim();
988  if (vec_dim == 1)
989  {
990  // scalar data
991  out << "<DataArray type=\"" << GetDataTypeString()
992  << "\" Name=\"" << it->first;
993  out << "\" NumberOfComponents=\"1\" format=\""
994  << GetDataFormatString() << "\" >\n";
995  for (int i = 0; i < mesh->GetNE(); i++)
996  {
998  mesh->GetElementBaseGeometry(i), ref_, 1);
999  it->second->GetValues(i, RefG->RefPts, val, pmat);
1000  for (int j = 0; j < val.Size(); j++)
1001  {
1002  if (pv_data_format == VTKFormat::ASCII)
1003  {
1004  out << ZeroSubnormal(val(j)) << '\n';
1005  }
1006  else if (pv_data_format == VTKFormat::BINARY)
1007  {
1008  bin_io::AppendBytes(buf, val(j));
1009  }
1010  else
1011  {
1012  bin_io::AppendBytes<float>(buf, float(val(j)));
1013  }
1014  }
1015  }
1016  }
1017  else
1018  {
1019  // vector data
1020  out << "<DataArray type=\"" << GetDataTypeString()
1021  << "\" Name=\"" << it->first;
1022  out << "\" NumberOfComponents=\"" << vec_dim << "\""
1023  << " format=\"" << GetDataFormatString() << "\" >" << '\n';
1024  for (int i = 0; i < mesh->GetNE(); i++)
1025  {
1026  RefG = GlobGeometryRefiner.Refine(
1027  mesh->GetElementBaseGeometry(i), ref_, 1);
1028 
1029  it->second->GetVectorValues(i, RefG->RefPts, vval, pmat);
1030 
1031  for (int jj = 0; jj < vval.Width(); jj++)
1032  {
1033  for (int ii = 0; ii < vval.Height(); ii++)
1034  {
1035  if (pv_data_format == VTKFormat::ASCII)
1036  {
1037  out << ZeroSubnormal(vval(ii,jj)) << ' ';
1038  }
1039  else if (pv_data_format == VTKFormat::BINARY)
1040  {
1041  bin_io::AppendBytes(buf, vval(ii,jj));
1042  }
1043  else
1044  {
1045  bin_io::AppendBytes<float>(buf, float(vval(ii,jj)));
1046  }
1047  }
1048  if (pv_data_format == VTKFormat::ASCII) { out << '\n'; }
1049  }
1050  }
1051  }
1052 
1053  if (IsBinaryFormat())
1054  {
1055  WriteVTKEncodedCompressed(out,buf.data(),buf.size(),compression);
1056  out << '\n';
1057  }
1058  out << "</DataArray>" << std::endl;
1059 }
1060 
1062 {
1063  pv_data_format = fmt;
1064 }
1065 
1067 {
1068  return pv_data_format != VTKFormat::ASCII;
1069 }
1070 
1071 void ParaViewDataCollection::SetHighOrderOutput(bool high_order_output_)
1072 {
1073  high_order_output = high_order_output_;
1074 }
1075 
1077 {
1078  MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
1079  "Compression level must be between -1 and 9 (inclusive).");
1080  compression = compression_level_;
1081 }
1082 
1084 {
1085  // If we are enabling compression, and it was disabled previously, use the
1086  // default compression level. Otherwise, leave the compression level
1087  // unchanged.
1088  if (compression_ && compression == 0)
1089  {
1090  SetCompressionLevel(-1);
1091  }
1092 }
1093 
1095 {
1096  if (pv_data_format == VTKFormat::ASCII)
1097  {
1098  return "ascii";
1099  }
1100  else
1101  {
1102  return "binary";
1103  }
1104 }
1105 
1107 {
1108  if (pv_data_format==VTKFormat::ASCII || pv_data_format==VTKFormat::BINARY)
1109  {
1110  return "Float64";
1111  }
1112  else
1113  {
1114  return "Float32";
1115  }
1116 }
1117 
1118 } // end namespace MFEM
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:245
virtual void SaveMesh()
Save the mesh, creating the collection directory.
void SaveOneField(const FieldMapIterator &it)
Save one field to disk, assuming the collection directory exists.
virtual void Print(std::ostream &out=mfem::out) const
Definition: mesh.hpp:1234
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
const IntegrationRule & GetElementIntRule(int idx) const
Get the IntegrationRule associated with mesh element idx.
Definition: gridfunc.hpp:767
int format
Output mesh format: see the Format enumeration.
int error
Error state.
void SetDataFormat(VTKFormat fmt)
double GetTime() const
Get physical time (for time-dependent simulations)
bool appendRankToFileName
Append rank to any output file names.
iterator begin()
Returns a begin iterator to the registered fields.
virtual void RegisterQField(const std::string &q_field_name, QuadratureFunction *qf)
Add a QuadratureFunction to the collection.
void DeleteAll()
Delete data owned by the DataCollection including field information.
std::string to_string(int i)
Convert an integer to an std::string.
Definition: text.hpp:51
const char * GetDataTypeString() const
iterator end()
Returns an end iterator to the registered fields.
int pad_digits_cycle
Number of digits used for the cycle and MPI rank in filenames.
GFieldMap::iterator FieldMapIterator
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:71
const std::string & GetCollectionName() const
Get the name of the collection.
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition: fe.hpp:319
int VectorDim() const
Definition: gridfunc.cpp:300
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
int Size() const
Returns the size of the vector.
Definition: vector.hpp:160
Helper class for VisIt visualization data.
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:760
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:737
virtual void Save()
Save the collection and a VisIt root file.
std::string GetVisItRootString()
Prepare the VisIt root file in JSON format for the current collection.
void PrintVTU(std::ostream &out, int ref=1, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0, bool bdr_elements=false)
Definition: mesh.cpp:9130
bool own_data
Should the collection delete its mesh and fields.
virtual void SetCompression(bool comp)
Set the flag for use of gz compressed files.
int main(int argc, char *argv[])
Definition: ex1.cpp:66
void ParseVisItRootString(const std::string &json)
Read in a VisIt root file in JSON format.
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:834
virtual void SaveQField(const std::string &q_field_name)
Save one q-field, assuming the collection directory already exists.
T ZeroSubnormal(T val)
Definition: vector.hpp:419
MPI_Comm m_comm
Associated MPI communicator.
virtual void Load(int cycle_=0) override
Load the collection - not implemented in the ParaView writer.
double time
Physical time (for time-dependent simulations)
std::map< std::string, VisItFieldInfo >::iterator FieldInfoMapIterator
int GetNRanks() const
Definition: pmesh.hpp:237
iterator find(const std::string &fname)
Returns an iterator to the field fname.
void SetCompressionLevel(int compression_level_)
std::string GetMeshShortFileName() const
Mesh * mesh
The (common) mesh for the collected fields.
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:427
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:763
void SaveOneQField(const QFieldMapIterator &it)
Save one q-field to disk, assuming the collection directory exists.
void SaveQFieldVTU(std::ostream &out, int ref, const QFieldMapIterator &it)
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection.
bool serial
Serial or parallel run? False iff mesh is a ParMesh.
int cycle
Time cycle; for time-dependent simulations cycle &gt;= 0, otherwise = -1.
VisItDataCollection(const std::string &collection_name, Mesh *mesh_=NULL)
Constructor. The collection name is used when saving the data.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:65
virtual void Save()
Save the collection to disk.
std::string to_padded_string(int i, int digits)
Convert an integer to a 0-padded string with the given number of digits.
Definition: text.hpp:63
int to_int(const std::string &str)
Convert a string to an int.
Definition: text.hpp:71
void SaveDataVTU(std::ostream &out, int ref)
QuadratureSpace * GetSpace() const
Get the associated QuadratureSpace.
Definition: gridfunc.hpp:711
VTKFormat
Definition: vtk.hpp:22
void SaveGFieldVTU(std::ostream &out, int ref_, const FieldMapIterator &it)
virtual void SetFormat(int fmt)
Set the desired output mesh and data format.
static int create_directory(const std::string &dir_name, const Mesh *mesh, int myid)
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1520
void Register(const std::string &fname, T *field, bool own_data)
Register field field with name fname.
DataCollection(const std::string &collection_name, Mesh *mesh_=NULL)
Initialize the collection with its name and Mesh.
void DeleteData()
Delete data owned by the DataCollection keeping field information.
void SetLevelsOfDetail(int levels_of_detail)
Set VisIt parameter: default levels of detail for the MultiresControl.
IntegrationRule RefPts
Definition: geom.hpp:243
void SetHighOrderOutput(bool high_order_output_)
static const int pad_digits_default
Default value for pad_digits_*.
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition: geom.cpp:942
void SetCompression(bool compression_) override
virtual int GetRefinementLevelFromElems(Geometry::Type geom, int Npts)
Get the Refinement level based on number of elements.
Definition: geom.cpp:1479
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:595
int Dimension() const
Definition: mesh.hpp:788
const char * GetDataFormatString() const
virtual void Load(int cycle_=0)
Load the collection based on its VisIt data (described in its root file)
int GetOrder() const
If all orders are identical, return that number. Otherwise, return NURBSFECollection::VariableOrder.
Definition: nurbs.hpp:348
int SpaceDimension() const
Definition: mesh.hpp:789
std::map< std::string, VisItFieldInfo > field_info_map
int GetMyRank() const
Definition: pmesh.hpp:238
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:316
QFieldMap::iterator QFieldMapIterator
int precision
Precision (number of digits) used for the text output of doubles.
MPI_Comm GetComm() const
Definition: pmesh.hpp:236
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
bool IsBinaryFormat() const
Returns true if the output format is BINARY or BINARY32, false if ASCII.
int myid
MPI rank (in parallel)
virtual void SaveField(const std::string &field_name)
Save one field, assuming the collection directory already exists.
static const int precision_default
Default value for precision.
void SetMaxLevelsOfDetail(int max_levels_of_detail)
Set VisIt parameter: maximum levels of detail for the MultiresControl.
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection and update the root file.
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:203
virtual ~DataCollection()
Delete the mesh and fields if owned by the collection.
std::string GetFieldFileName(const std::string &field_name) const
void clear()
Clears the map of registered fields without reclaiming memory.
void SaveRootFile()
Save a VisIt root file for the collection.
const char * VTKByteOrder()
Definition: vtk.cpp:461
ParaViewDataCollection(const std::string &collection_name, mfem::Mesh *mesh_=NULL)
Constructor. The collection name is used when saving the data.
std::string prefix_path
A path where the directory with results is saved. If not empty, it has &#39;/&#39; at the end...
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:1798
void WriteVTKEncodedCompressed(std::ostream &out, const void *bytes, uint32_t nbytes, int compression_level)
Definition: vtk.cpp:418
void AppendBytes(std::vector< char > &vec, const T &val)
Definition: binaryio.hpp:45
virtual void RegisterQField(const std::string &q_field_name, QuadratureFunction *qf)
Add a quadrature function to the collection and update the root file.
virtual void Load(int cycle_=0)
Load the collection. Not implemented in the base class DataCollection.
void SetLevelsOfDetail(int levels_of_detail_)
std::string GetMeshFileName() const
Vector data type.
Definition: vector.hpp:51
void LoadVisItRootFile(const std::string &root_name)
virtual void SetMesh(Mesh *new_mesh)
Set/change the mesh associated with the collection.
virtual void Save() override
std::string name
Name of the collection, used as a directory name when saving.
virtual void SetMesh(Mesh *new_mesh)
Set/change the mesh associated with the collection.
void DeleteAll()
Delete all data owned by VisItDataCollection including field data information.
void DeleteData(bool own_data)
Clear all associations between names and fields.
Class for parallel grid function.
Definition: pgridfunc.hpp:32
double time_step
Time step i.e. delta_t (for time-dependent simulations)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
int num_procs
Number of MPI ranks (in parallel)
void ParPrint(std::ostream &out) const
Save the mesh in a parallel mesh format.
Definition: pmesh.cpp:5292
Class for parallel meshes.
Definition: pmesh.hpp:32
Class representing a function through its values (scalar or vector) at quadrature points...
Definition: gridfunc.hpp:670
void SetPrefixPath(const std::string &prefix)
Set the path where the DataCollection will be saved.