COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
Writer.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2013 von Karman Institute for Fluid Dynamics, Belgium
2 //
3 // This software is distributed under the terms of the
4 // GNU Lesser General Public License version 3 (LGPLv3).
5 // See doc/lgpl.txt and doc/gpl.txt for the license text.
6 
7 #include <iostream>
8 #include <set>
9 #include <boost/lexical_cast.hpp>
11 #include "common/Foreach.hpp"
12 #include "common/Log.hpp"
13 #include "common/OptionList.hpp"
14 #include "common/PropertyList.hpp"
15 #include "common/OptionT.hpp"
16 #include "common/PE/Comm.hpp"
17 #include "common/Builder.hpp"
20 #include "common/List.hpp"
21 
22 #include "mesh/smurf/Writer.hpp"
23 #include "mesh/GeoShape.hpp"
24 #include "mesh/Mesh.hpp"
25 #include "mesh/Region.hpp"
26 #include "mesh/Dictionary.hpp"
27 #include "mesh/Space.hpp"
28 #include "mesh/Field.hpp"
29 #include "mesh/Connectivity.hpp"
30 #include "mesh/Functions.hpp"
31 #include "mesh/MeshMetadata.hpp"
32 
34 
35 using namespace cf3::common;
36 
37 namespace cf3 {
38 namespace mesh {
39 namespace smurf {
40 
41 #define CF3_BREAK_LINE(f,x) { if( x+1 % 10) { f << "\n"; } }
42 
44 
46 
48 
49 Writer::Writer( const std::string& name )
50 : MeshWriter(name)
51 {
52 
53  options().add("cell_centred",true)
54  .description("True if discontinuous fields are to be plotted as cell-centred fields");
55 }
56 
58 
59 std::vector<std::string> Writer::get_extensions()
60 {
61  std::vector<std::string> extensions;
62  extensions.push_back(".smurf");
63  return extensions;
64 }
65 
67 
69 {
70 
71  const common::Table<Real>& coordinates = m_mesh->geometry_fields().coordinates();
72  const Uint
73  dimension = coordinates.row_size(),
74  nb_nodes = coordinates.size();
75 
76  boost::filesystem::path path(m_file_path.path());
77  if (PE::Comm::instance().size() > 1)
78  path = boost::filesystem::basename(path) + "_P" + to_str(PE::Comm::instance().rank()) + boost::filesystem::extension(path);
79 
80  SmURF::MeshWriter mwriter(path.string(), SmURF::DOUBLE, false, 107, m_mesh->metadata().properties().value<Real>("time")); // add solution time here if needed !
81 
82  // Get variable names
83  std::vector< std::string > vn;
84  std::vector< std::vector<double> > vv;
85  vn.reserve(dimension+m_fields.size());
86  vv.reserve(vn.size());
87 
88  // loop over coordinates
89  for (Uint d = 0; d < dimension; ++d)
90  {
91  std::vector<double> var; var.reserve(nb_nodes);
92  for (int j=0; j<coordinates.size(); ++j)
93  {
94  cf3_assert(j<coordinates.size());
95  var.push_back(coordinates[j][d]);
96  }
97  vv.push_back(var);
98  vn.push_back("x"+boost::lexical_cast<std::string>(d));
99  CFdebug << "smurf: adding coordinate \"" << vn.back() << "\"" << CFendl;
100  }
101 
103  {
104  const Field& field = *field_ptr;
105  Uint var_idx(0);
106  for (Uint iVar=0; iVar<field.nb_vars(); ++iVar)
107  {
108  VarType var_type = field.var_length(iVar);
109  std::string var_name = field.var_name(iVar);
110  CFdebug << "smurf: adding variable \"" << var_name << "\"" << CFendl;
111 
112  for (Uint i=0; i<static_cast<Uint>(var_type); ++i)
113  {
114  if (field.continuous())
115  {
116  // Continuous field with different space than geometry
117  if ( &field.dict() == &m_mesh->geometry_fields() )
118  {
119  std::vector<double> var; var.reserve(nb_nodes);
120  for (Uint n=0; n<nb_nodes; ++n)
121  {
122  var.push_back(field[n][var_idx]);
123  }
124  vv.push_back(var);
125  vn.push_back(var_name);
126  }
127 
128 #if 0
129  // Continuous field with different space than geometry
130  else
131  {
132  if (field.dict().defined_for_entities(elements.handle<Entities>()) )
133  {
134  const Space& field_space = field.space(elements);
135  RealVector field_data (field_space.shape_function().nb_nodes());
136 
137  std::vector<Real> nodal_data(used_nodes.size(),0.);
138 
139  RealMatrix interpolation(elements.geometry_space().shape_function().nb_nodes(),field_space.shape_function().nb_nodes());
140  const RealMatrix& geometry_local_coords = elements.geometry_space().shape_function().local_coordinates();
141  const ShapeFunction& sf = field_space.shape_function();
142  for (Uint g=0; g<interpolation.rows(); ++g)
143  {
144  interpolation.row(g) = sf.value(geometry_local_coords.row(g));
145  }
146 
147  // Compute interpolated data in the vector nodal_data
148  for (Uint e=0; e<elements.size(); ++e)
149  {
150  // Skip this element if it is a ghost cell and overlap is disabled
151  if (m_enable_overlap || !elements.is_ghost(e))
152  {
153  // get the node indices of this element
154  Connectivity::ConstRow field_index = field_space.connectivity()[e];
155 
157  for (Uint iState=0; iState<field_space.shape_function().nb_nodes(); ++iState)
158  {
159  field_data[iState] = field[field_index[iState]][var_idx];
160  }
161 
163  RealVector geometry_field_data = interpolation*field_data;
164 
165  Connectivity::ConstRow geom_nodes = elements.geometry_space().connectivity()[e];
166  cf3_assert(geometry_field_data.size()==geom_nodes.size());
168  for (Uint g=0; g<geom_nodes.size(); ++g)
169  {
170  const Uint geom_node = geom_nodes[g];
171  const Uint node_idx = zone_node_idx[geom_node]-1;
172  cf3_assert(node_idx < nodal_data.size());
173  nodal_data[node_idx] = geometry_field_data[g];
174  }
175  }
176  }
177  vv.push_back(nodal_data);
178  vv.push_back(var_name);
179  }
180  }
181 #else
182  else
183  {
184  throw NotImplemented(FromHere(), "Continuous field with different space than geometry: not implemented");
185  }
186 #endif
187  }
188 #if 0
189  // Discontinuous fields
190  else
191  {
192  if (field.dict().defined_for_entities(elements.handle<Entities>()))
193  {
194  const Space& field_space = field.space(elements);
195  RealVector field_data (field_space.shape_function().nb_nodes());
196 
197  if (options().value<bool>("cell_centred"))
198  {
199  boost::shared_ptr< ShapeFunction > P0_cell_centred = boost::dynamic_pointer_cast<ShapeFunction>(build_component("cf3.mesh.LagrangeP0."+to_str(elements.element_type().shape_name()),"tmp_shape_func"));
200 
201  for (Uint e=0; e<elements.size(); ++e)
202  {
203  if (m_enable_overlap || !elements.is_ghost(e))
204  {
205  Connectivity::ConstRow field_index = field_space.connectivity()[e];
207  for (Uint iState=0; iState<field_space.shape_function().nb_nodes(); ++iState)
208  {
209  field_data[iState] = field[field_index[iState]][var_idx];
210  }
211 
213  RealVector local_coords = P0_cell_centred->local_coordinates().row(0);
214 
216  Real cell_centred_data = field_space.shape_function().value(local_coords)*field_data;
217 
219  file << cell_centred_data << " ";
220  CF3_BREAK_LINE(file,e);
221  }
222  }
223  file << "\n";
224  }
225  else
226  {
227  std::vector<Real> nodal_data(used_nodes.size(),0.);
228  std::vector<Uint> nodal_data_count(used_nodes.size(),0u);
229 
230  RealMatrix interpolation(elements.geometry_space().shape_function().nb_nodes(),field_space.shape_function().nb_nodes());
231  const RealMatrix& geometry_local_coords = elements.geometry_space().shape_function().local_coordinates();
232  const ShapeFunction& sf = field_space.shape_function();
233  for (Uint g=0; g<interpolation.rows(); ++g)
234  {
235  interpolation.row(g) = sf.value(geometry_local_coords.row(g));
236  }
237 
238  for (Uint e=0; e<elements.size(); ++e)
239  {
240  Connectivity::ConstRow field_index = field_space.connectivity()[e];
241 
243  for (Uint iState=0; iState<field_space.shape_function().nb_nodes(); ++iState)
244  {
245  field_data[iState] = field[field_index[iState]][var_idx];
246  }
247 
249  RealVector geometry_field_data = interpolation*field_data;
250 
251  Connectivity::ConstRow geom_nodes = elements.geometry_space().connectivity()[e];
252  cf3_assert(geometry_field_data.size()==geom_nodes.size());
254  for (Uint g=0; g<geom_nodes.size(); ++g)
255  {
256  const Uint geom_node = geom_nodes[g];
257  if (zone_node_idx.find(geom_node) != zone_node_idx.end())
258  {
259  const Uint node_idx = zone_node_idx[geom_node]-1;
260  cf3_assert(node_idx < nodal_data.size());
261  const Real accumulated_weight = nodal_data_count[node_idx]/(nodal_data_count[node_idx]+1.0);
262  const Real add_weight = 1.0/(nodal_data_count[node_idx]+1.0);
263  nodal_data[node_idx] = accumulated_weight*nodal_data[node_idx] + add_weight*geometry_field_data[g];
264  ++nodal_data_count[node_idx];
265  }
266  }
267  }
268 
269  for (Uint n=0; n<nodal_data.size(); ++n)
270  {
271  file << nodal_data[n] << " ";
272  CF3_BREAK_LINE(file,n)
273  }
274  file << "\n";
275 
276  }
277  }
278  else
279  {
280  // field not defined for this zone, so write zeros
281  if (options().value<bool>("cell_centred"))
282  file << nb_elems << "*" << 0.;
283  else
284  file << used_nodes.size() << "*" << 0.;
285  }
286  }
287 #else
288  else
289  {
290  throw NotSupported(FromHere(), "Discontinuous fields not supported");
291  }
292 #endif
293  var_idx++;
294  }
295  }
296  }
297 
298  mwriter.writeMainHeader("COOLFluiD_Mesh_Data",vn);
299 
300  // loop over the element types
301  // and create a zone in the tecplot file for each element type
302  Uint zone_idx=0;
304  {
305  Entities const& elements = *elements_h;
306  const ElementType& etype = elements.element_type();
307 
308  Uint nb_elems = elements.size();
309 
310  if(m_enable_overlap == false)
311  {
312  Uint nb_ghost_elems = 0;
313  for (Uint e=0; e<nb_elems; ++e)
314  {
315  if (elements.is_ghost(e))
316  ++nb_ghost_elems;
317  }
318  nb_elems -= nb_ghost_elems;
319  }
320 
321  std::string zone_name = elements.parent()->uri().path();
322  boost::algorithm::replace_first(zone_name,m_mesh->topology().uri().path()+"/","");
323  std::set<std::string> zone_names;
324  if (zone_names.count(zone_name) == 0)
325  {
326  zone_idx++;
327  zone_names.insert(zone_name);
328  }
329 
330  // tecplot doesn't handle zones with 0 elements
331  // which can happen in parallel, so skip them
332  if (nb_elems == 0) continue;
333 
334  if (etype.order() > 1)
335  {
336  throw NotImplemented(FromHere(), "Tecplot can only output P1 elements. A new P1 space should be created, and used as geometry space");
337  }
338 
339  boost::shared_ptr< common::List<Uint> > used_nodes_ptr = mesh::build_used_nodes_list(elements,m_mesh->geometry_fields(),m_enable_overlap);
340  common::List<Uint> const& used_nodes = *used_nodes_ptr;
341 
342  // print zone header,
343  // one zone per element type per cpu
344  // therefore the title is dependent on those parameters
345  CFdebug << "smurf: writing zone header \"" << zone_name << "\"" << CFendl
346  << " tec_type: " << zone_type(etype) << CFendl
347  << " nb_elems: " << nb_elems << CFendl;
348  mwriter.writeZoneHeader(zone_type(etype),SmURF::BLOCK,zone_name, nb_nodes, nb_elems, 1, zone_idx);
349 
350  // TODO: implement cell-centered vars
351 #if 0
352  if (cell_centered_var_ids.size() && options().value<bool>("cell_centred"))
353  {
354  CFerror << "Not implemented for cellcentered" << CFendl;
355  file << ",VARLOCATION=(["<<cell_centered_var_ids[0];
356  for (Uint i=1; i<cell_centered_var_ids.size(); ++i)
357  file << ","<<cell_centered_var_ids[i];
358  file << "]=CELLCENTERED)";
359  }
360 #endif
361  }
362 
363  Uint i = 0;
365  {
366  Entities const& elements = *elements_h;
367  const ElementType& etype = elements.element_type();
368 
369  Uint nb_elems = elements.size();
370 
371  if(m_enable_overlap == false)
372  {
373  Uint nb_ghost_elems = 0;
374  for (Uint e=0; e<nb_elems; ++e)
375  {
376  if (elements.is_ghost(e))
377  ++nb_ghost_elems;
378  }
379  nb_elems -= nb_ghost_elems;
380  }
381 
382  // tecplot doesn't handle zones with 0 elements
383  // which can happen in parallel, so skip them
384  if (nb_elems == 0) continue;
385 
386  // write connectivity
387  const Connectivity& connectivity = elements.geometry_space().connectivity();
388  std::vector<std::vector<unsigned> > ve; ve.reserve(connectivity.size());
389 
390  for (Uint e=0; e<elements.size(); ++e)
391  {
392  if (m_enable_overlap || !elements.is_ghost(e))
393  {
394  std::vector<unsigned> element; element.reserve(connectivity.row_size());
395  boost_foreach ( Uint n, connectivity[e])
396  element.push_back(n);
397  ve.push_back(element);
398  }
399  }
400 
401  if (etype.shape() == GeoShape::POINT) {
402 
403  // these are represented by a FELINESEG, with coalesced nodes
404  for (unsigned c=0; c<ve.size(); ++c) {
405  const std::vector< unsigned > eng = ve[c]; // element nodes, original (gambit)
406  std::vector< unsigned >& ent = ve[c]; // ..., modified (tecplot)
407  ent.resize(2);
408  ent[0] = eng[0];
409  ent[1] = eng[0];
410  }
411 
412  }
413  else if (etype.shape() == GeoShape::HEXA) { //*2
414 
415  // these are represented by a FEBRICK, with coalesced nodes
416  for (unsigned c=0; c<ve.size(); ++c) {
417  const std::vector< unsigned > eng = ve[c]; // element nodes, original (gambit)
418  std::vector< unsigned >& ent = ve[c]; // ..., modified (tecplot)
419  ent.resize(8);
420  ent[0] = eng[0];
421  ent[1] = eng[1];
422  ent[2] = eng[2];
423  ent[3] = eng[2];
424  ent[4] = eng[3];
425  ent[5] = eng[4];
426  ent[6] = eng[5];
427  ent[7] = eng[5];
428  }
429 
430  }
431  else if (etype.shape() == GeoShape::PYRAM) { //*3
432 
433  // these are represented by a FEBRICK, with coalesced nodes
434  for (unsigned c=0; c<ve.size(); ++c) {
435  const std::vector< unsigned > eng = ve[c]; // element nodes, original (gambit)
436  std::vector< unsigned >& ent = ve[c]; // ..., modified (tecplot)
437  ent.resize(8);
438  ent[0] = eng[0];
439  ent[1] = eng[1];
440  ent[2] = eng[3];
441  ent[3] = eng[2];
442  ent[4] = eng[4];
443  ent[5] = eng[4];
444  ent[6] = eng[4];
445  ent[7] = eng[4];
446  }
447 
448  }
449  else if (etype.shape() == GeoShape::HEXA) { //*1
450 
451  // these need renumbering
452  for (unsigned c=0; c<ve.size(); ++c) {
453  std::swap(ve[c][2],ve[c][3]);
454  std::swap(ve[c][6],ve[c][7]);
455  }
456 
457  }
458 
459  const int sharefrom = (zone_type(etype)==SmURF::ORDERED || !i? -1:0);
460  mwriter.writeZoneData(zone_type(etype),SmURF::BLOCK,zone_type(etype)==SmURF::ORDERED?std::vector<std::vector<unsigned> >(0):ve,vv,sharefrom);
461  ++i;
462  }
463 }
464 
466 
468 {
469  return
470  (etype.shape() == GeoShape::POINT? SmURF::FELINESEG :
471  (etype.shape() == GeoShape::LINE ? SmURF::FELINESEG :
474  (etype.shape() == GeoShape::HEXA ? SmURF::FEBRICK :
476  (etype.shape() == GeoShape::PRISM? SmURF::FEBRICK :
477  (etype.shape() == GeoShape::PYRAM? SmURF::FEBRICK :
478  SmURF::ORDERED ))))))));
479 }
481 
482 } // smurf
483 } // mesh
484 } // cf3
const ShapeFunction & shape_function() const
Definition: Space.cpp:102
std::string name(ComponentWrapper &self)
std::string var_name(Uint i=0) const
Definition: Field.cpp:69
boost::shared_ptr< Component > build_component(const std::string &builder_name, const std::string &name, const std::string &factory_type_name)
Definition: Component.cpp:1200
Safe pointer to an object. This is the supported method for referring to components.
Definition: Handle.hpp:39
common::ComponentBuilder< smurf::Writer, MeshWriter, LibSmurf > smurfWriter_Builder
Definition: Writer.cpp:45
Helper class to create the Builder and place it in the factory.
Definition: Builder.hpp:212
Space & geometry_space() const
Definition: Entities.hpp:94
bool continuous() const
Definition: Field.cpp:235
bool m_enable_overlap
If true, writing of overlap will be enabled.
Definition: MeshWriter.hpp:93
#define CF3_BREAK_LINE(f, x)
Definition: Writer.cpp:41
void writeZoneData(const ZoneType &type, const ZonePack &pack, const std::vector< std::vector< unsigned > > &ve, const std::vector< std::vector< double > > &vv=std::vector< std::vector< double > >(), const int sharefrom=0)
Definition: smurf.cpp:164
Handle< Mesh const > m_mesh
Handle to configured mesh.
Definition: MeshWriter.hpp:89
std::string path() const
Definition: URI.cpp:253
std::vector< Uint > used_nodes(const mesh::Region &region, const mesh::Dictionary &dict)
#define cf3_assert(a)
Definition: Assertions.hpp:93
ElementType & element_type() const
return the elementType
Definition: Entities.cpp:116
void writeMainHeader(const std::string &htitle, const std::vector< std::string > &hvnames)
Definition: smurf.cpp:92
ZoneType
Definition: smurf.h:15
bool is_ghost(const Uint idx) const
Definition: Entities.cpp:197
#define boost_foreach
lowercase version of BOOST_FOREACH
Definition: Foreach.hpp:16
bool defined_for_entities(const Handle< Entities const > &entities) const
Definition: Dictionary.cpp:449
common::URI m_file_path
File path to be configured.
Definition: MeshWriter.hpp:86
Uint nb_vars() const
Definition: Field.cpp:55
#define CFendl
Definition: Log.hpp:109
Conversions from and to std::string.
Real e()
Definition of the Unit charge [C].
Definition: Consts.hpp:30
virtual void write()
Definition: Writer.cpp:68
virtual std::vector< std::string > get_extensions()
Definition: Writer.cpp:59
Dictionary & dict() const
Definition: Field.cpp:118
Common_API std::string to_str(const T &v)
Converts to std::string.
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic > RealMatrix
Dynamic sized matrix of Real scalars.
Definition: MatrixTypes.hpp:22
Uint size() const
Definition: Table.hpp:127
void writeZoneHeader(const ZoneType &type, const ZonePack &pack, const std::string &title, const unsigned I=1, const unsigned J=1, const unsigned K=1, const int &strand_id=int(-2))
Definition: smurf.cpp:113
Uint size() const
return the number of elements
Definition: Entities.cpp:161
Handle< Component > parent() const
Definition: Component.cpp:256
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealVector
Dynamic sized column vector.
Definition: MatrixTypes.hpp:25
SmURF::ZoneType zone_type(const ElementType &etype) const
Definition: Writer.cpp:467
GeoShape::Type shape() const
Definition: ElementType.hpp:64
const Handle< Space const > & space(const Handle< Entities const > &entities) const
Definition: Field.cpp:248
TableConstRow< Uint >::type ConstRow
the const type of a row in the internal structure of the table
Definition: Table.hpp:59
VarType var_length(const std::string &vname) const
Return the length (in number of Real values occupied in the data row) of the variable of the given na...
Definition: Field.cpp:104
Top-level namespace for coolfluid.
Definition: Action.cpp:18
virtual Uint nb_nodes() const =0
const TYPE value(const std::string &opt_name) const
Get the value of the option with given name.
Definition: OptionList.hpp:104
Uint row_size(Uint i=0) const
Definition: Table.hpp:133
boost::proto::terminal< SFOp< CoordinatesOp > >::type const coordinates
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
virtual RealRowVector value(const RealVector &local_coordinate) const =0
Compute the shape function values in the given local coordinate.
RowArrayRef row(const Uint r)
Definition: Field.cpp:283
boost::shared_ptr< List< Uint > > build_used_nodes_list(const std::vector< Handle< Entities const > > &entities_vector, const Dictionary &dictionary, const bool include_ghost_elems, const bool follow_periodic_links)
Create a List containing unique entries of all the nodes used by a vector of entities...
Definition: Functions.cpp:24
#define CFerror
Definition: Log.hpp:105
OptionList & options()
Definition: Component.cpp:856
std::vector< Handle< Field const > > m_fields
Handle to configured fields.
Definition: MeshWriter.hpp:90
SelectOptionType< T >::type & add(const std::string &name, const T &default_value=T())
Definition: OptionList.hpp:45
std::vector< Handle< Entities const > > m_filtered_entities
Handle to selected entities.
Definition: MeshWriter.hpp:92
#define CFdebug
Definition: Log.hpp:107
Space component class.
Definition: Space.hpp:59
Most basic kernel library.
Definition: Action.cpp:19
Connectivity & connectivity()
connectivity table to dictionary entries
Definition: Space.hpp:110
VarType
Variable types.
Definition: Defs.hpp:23
#define FromHere()
Send comments to:
COOLFluiD Web Admin