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>
10 #include "common/Foreach.hpp"
11 #include "common/Log.hpp"
12 #include "common/OptionList.hpp"
13 #include "common/PropertyList.hpp"
14 #include "common/OptionT.hpp"
15 #include "common/PE/Comm.hpp"
16 #include "common/Builder.hpp"
19 #include "common/List.hpp"
20 
21 #include "mesh/tecplot/Writer.hpp"
22 #include "mesh/GeoShape.hpp"
23 #include "mesh/Mesh.hpp"
24 #include "mesh/Region.hpp"
25 #include "mesh/Dictionary.hpp"
26 #include "mesh/Space.hpp"
27 #include "mesh/Field.hpp"
28 #include "mesh/Connectivity.hpp"
29 #include "mesh/Functions.hpp"
30 #include "mesh/MeshMetadata.hpp"
31 
33 
34 using namespace cf3::common;
35 
36 namespace cf3 {
37 namespace mesh {
38 namespace tecplot {
39 
40 #define CF3_BREAK_LINE(f,x) { if( x+1 % 10) { f << "\n"; } }
41 
43 
45 
47 
48 Writer::Writer( const std::string& name )
49 : MeshWriter(name)
50 {
51 
52  options().add("cell_centred",true)
53  .description("True if discontinuous fields are to be plotted as cell-centred fields");
54 }
55 
57 
58 std::vector<std::string> Writer::get_extensions()
59 {
60  std::vector<std::string> extensions;
61  extensions.push_back(".plt");
62  return extensions;
63 }
64 
66 
68 {
69  // if the file is present open it
70  boost::filesystem::fstream file;
71  boost::filesystem::path path(m_file_path.path());
72  if (PE::Comm::instance().size() > 1)
73  {
74  path = boost::filesystem::basename(path) + "_P" + to_str(PE::Comm::instance().rank()) + boost::filesystem::extension(path);
75  }
76 // CFLog(VERBOSE, "Opening file " << path.string() << "\n");
77  file.open(path,std::ios_base::out);
78  if (!file) // didn't open so throw exception
79  {
80  throw boost::filesystem::filesystem_error( path.string() + " failed to open",
81  boost::system::error_code() );
82  }
83 
84 
85  write_file(file);
86 
87  file.close();
88 
89 }
91 
92 void Writer::write_file(std::fstream& file)
93 {
94  file << "TITLE = COOLFluiD Mesh Data" << "\n";
95  file << "VARIABLES = ";
96 
97  Uint dimension = m_mesh->geometry_fields().coordinates().row_size();
98  // write the coordinate variable names
99  for (Uint i = 0; i < dimension ; ++i)
100  {
101  file << " \"x" << i << "\" ";
102  }
103 
104  std::vector<Uint> cell_centered_var_ids;
105  Uint zone_var_id(dimension);
107  {
108  const Field& field = *field_ptr;
109  for (Uint iVar=0; iVar<field.nb_vars(); ++iVar)
110  {
111  VarType var_type = field.var_length(iVar);
112  std::string var_name = field.var_name(iVar);
113 
114  if ( static_cast<Uint>(var_type) > 1)
115  {
116  for (Uint i=0; i<static_cast<Uint>(var_type); ++i)
117  {
118  file << " \"" << var_name << "["<<i<<"]\"";
119  ++zone_var_id;
120  if (field.discontinuous())
121  cell_centered_var_ids.push_back(zone_var_id);
122  }
123  }
124  else
125  {
126  file << " \"" << var_name <<"\"";
127  ++zone_var_id;
128  if (field.discontinuous())
129  cell_centered_var_ids.push_back(zone_var_id);
130  }
131  }
132  }
133  file << "\n";
134 
135 
136  // loop over the element types
137  // and create a zone in the tecplot file for each element type
138 // std::map<Handle<Component const>,Uint> zone_id;
139  Uint zone_idx=0;
141  {
142  Entities const& elements = *elements_h;
143  const ElementType& etype = elements.element_type();
144 
145  Uint nb_elems = elements.size();
146 
147  if(m_enable_overlap == false)
148  {
149  Uint nb_ghost_elems = 0;
150  for (Uint e=0; e<nb_elems; ++e)
151  {
152  if (elements.is_ghost(e))
153  ++nb_ghost_elems;
154  }
155  nb_elems -= nb_ghost_elems;
156  }
157 
158  std::string zone_name = elements.parent()->uri().path();
159  boost::algorithm::replace_first(zone_name,m_mesh->topology().uri().path()+"/","");
160  std::set<std::string> zone_names;
161  if (zone_names.count(zone_name) == 0)
162  {
163  zone_idx++;
164  zone_names.insert(zone_name);
165  }
166 // zone_id[elements.handle<Component>()] = zone_idx++;
167 
168  // tecplot doesn't handle zones with 0 elements
169  // which can happen in parallel, so skip them
170  if (nb_elems == 0)
171  continue;
172 
173  if (etype.order() > 1)
174  {
175  throw NotImplemented(FromHere(), "Tecplot can only output P1 elements. A new P1 space should be created, and used as geometry space");
176  }
177 
178  boost::shared_ptr< common::List<Uint> > used_nodes_ptr = mesh::build_used_nodes_list(elements,m_mesh->geometry_fields(),m_enable_overlap);
179  common::List<Uint>& used_nodes = *used_nodes_ptr;
180  std::map<Uint,Uint> zone_node_idx;
181  for (Uint n=0; n<used_nodes.size(); ++n)
182  zone_node_idx[ used_nodes[n] ] = n+1;
183 
184  const Uint nbCellsInType = elements.size();
185 
186 
187  // print zone header,
188  // one zone per element type per cpu
189  // therefore the title is dependent on those parameters
190  file << "ZONE "
191  << " T=\"STEP"<<m_mesh->metadata().properties().value<Uint>("iter") << ":" << zone_name << "\""
192  << ", STRANDID="<<zone_idx
193  << ", SOLUTIONTIME="<<m_mesh->metadata().properties().value<Real>("time")
194  << ", N=" << used_nodes.size()
195  << ", E=" << nb_elems
196  << ", DATAPACKING=BLOCK"
197  << ", ZONETYPE=" << zone_type(etype);
198  if (cell_centered_var_ids.size() && options().value<bool>("cell_centred"))
199  {
200  file << ",VARLOCATION=(["<<cell_centered_var_ids[0];
201  for (Uint i=1; i<cell_centered_var_ids.size(); ++i)
202  file << ","<<cell_centered_var_ids[i];
203  file << "]=CELLCENTERED)";
204  }
205  file << "\n\n";
206 
207 
208  // fout << ", VARLOCATION=( [" << init_id << "]=CELLCENTERED )" ;
209  // else
210  // fout << ", VARLOCATION=( [" << init_id << "-" << end_id << "]=CELLCENTERED )" ;
211  // }
212 
213  file.setf(std::ios::scientific,std::ios::floatfield);
214  file.precision(12);
215 
216  // loop over coordinates
217  const common::Table<Real>& coordinates = m_mesh->geometry_fields().coordinates();
218  for (Uint d = 0; d < dimension; ++d)
219  {
220  file << "\n### variable x" << d << "\n\n"; // var name in comment
221  boost_foreach(Uint n, used_nodes.array())
222  {
223  cf3_assert(n<coordinates.size());
224  file << coordinates[n][d] << " ";
225  CF3_BREAK_LINE(file,n);
226  }
227  file << "\n";
228  }
229  file << "\n";
230 
231 
233  {
234  const Field& field = *field_ptr;
235  Uint var_idx(0);
236  for (Uint iVar=0; iVar<field.nb_vars(); ++iVar)
237  {
238  VarType var_type = field.var_length(iVar);
239  std::string var_name = field.var_name(iVar);
240  file << "\n### variable " << var_name << "\n\n"; // var name in comment
241 
242  for (Uint i=0; i<static_cast<Uint>(var_type); ++i)
243  {
244  if (field.continuous())
245  {
246  // Continuous field with different space than geometry
247  if ( &field.dict() == &m_mesh->geometry_fields() )
248  {
249  boost_foreach(Uint n, used_nodes.array())
250  {
251  file << field[n][var_idx] << " ";
252  CF3_BREAK_LINE(file,n);
253  }
254  file << "\n";
255  }
256  // Continuous field with different space than geometry
257  else
258  {
259  if (field.dict().defined_for_entities(elements.handle<Entities>()) )
260  {
261  const Space& field_space = field.space(elements);
262  RealVector field_data (field_space.shape_function().nb_nodes());
263 
264  std::vector<Real> nodal_data(used_nodes.size(),0.);
265 
266  RealMatrix interpolation(elements.geometry_space().shape_function().nb_nodes(),field_space.shape_function().nb_nodes());
267  const RealMatrix& geometry_local_coords = elements.geometry_space().shape_function().local_coordinates();
268  const ShapeFunction& sf = field_space.shape_function();
269  for (Uint g=0; g<interpolation.rows(); ++g)
270  {
271  interpolation.row(g) = sf.value(geometry_local_coords.row(g));
272  }
273 
274  // Compute interpolated data in the vector nodal_data
275  for (Uint e=0; e<elements.size(); ++e)
276  {
277  // Skip this element if it is a ghost cell and overlap is disabled
278  if (m_enable_overlap || !elements.is_ghost(e))
279  {
280  // get the node indices of this element
281  Connectivity::ConstRow field_index = field_space.connectivity()[e];
282 
284  for (Uint iState=0; iState<field_space.shape_function().nb_nodes(); ++iState)
285  {
286  field_data[iState] = field[field_index[iState]][var_idx];
287  }
288 
290  RealVector geometry_field_data = interpolation*field_data;
291 
292  Connectivity::ConstRow geom_nodes = elements.geometry_space().connectivity()[e];
293  cf3_assert(geometry_field_data.size()==geom_nodes.size());
295  for (Uint g=0; g<geom_nodes.size(); ++g)
296  {
297  const Uint geom_node = geom_nodes[g];
298  const Uint node_idx = zone_node_idx[geom_node]-1;
299  cf3_assert(node_idx < nodal_data.size());
300  nodal_data[node_idx] = geometry_field_data[g];
301  }
302  }
303  }
304  for (Uint n=0; n<nodal_data.size(); ++n)
305  {
306  file << nodal_data[n] << " ";
307  CF3_BREAK_LINE(file,n)
308  }
309  file << "\n";
310  }
311  }
312  }
313  // Discontinuous fields
314  else
315  {
316  if (field.dict().defined_for_entities(elements.handle<Entities>()))
317  {
318  const Space& field_space = field.space(elements);
319  RealVector field_data (field_space.shape_function().nb_nodes());
320 
321  if (options().value<bool>("cell_centred"))
322  {
323  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"));
324 
325  for (Uint e=0; e<elements.size(); ++e)
326  {
327  if (m_enable_overlap || !elements.is_ghost(e))
328  {
329  Connectivity::ConstRow field_index = field_space.connectivity()[e];
331  for (Uint iState=0; iState<field_space.shape_function().nb_nodes(); ++iState)
332  {
333  field_data[iState] = field[field_index[iState]][var_idx];
334  }
335 
337  RealVector local_coords = P0_cell_centred->local_coordinates().row(0);
338 
340  Real cell_centred_data = field_space.shape_function().value(local_coords)*field_data;
341 
343  file << cell_centred_data << " ";
344  CF3_BREAK_LINE(file,e);
345  }
346  }
347  file << "\n";
348  }
349  else
350  {
351  std::vector<Real> nodal_data(used_nodes.size(),0.);
352  std::vector<Uint> nodal_data_count(used_nodes.size(),0u);
353 
354  RealMatrix interpolation(elements.geometry_space().shape_function().nb_nodes(),field_space.shape_function().nb_nodes());
355  const RealMatrix& geometry_local_coords = elements.geometry_space().shape_function().local_coordinates();
356  const ShapeFunction& sf = field_space.shape_function();
357  for (Uint g=0; g<interpolation.rows(); ++g)
358  {
359  interpolation.row(g) = sf.value(geometry_local_coords.row(g));
360  }
361 
362  for (Uint e=0; e<elements.size(); ++e)
363  {
364  Connectivity::ConstRow field_index = field_space.connectivity()[e];
365 
367  for (Uint iState=0; iState<field_space.shape_function().nb_nodes(); ++iState)
368  {
369  field_data[iState] = field[field_index[iState]][var_idx];
370  }
371 
373  RealVector geometry_field_data = interpolation*field_data;
374 
375  Connectivity::ConstRow geom_nodes = elements.geometry_space().connectivity()[e];
376  cf3_assert(geometry_field_data.size()==geom_nodes.size());
378  for (Uint g=0; g<geom_nodes.size(); ++g)
379  {
380  const Uint geom_node = geom_nodes[g];
381  if (zone_node_idx.find(geom_node) != zone_node_idx.end())
382  {
383  const Uint node_idx = zone_node_idx[geom_node]-1;
384  cf3_assert(node_idx < nodal_data.size());
385  const Real accumulated_weight = nodal_data_count[node_idx]/(nodal_data_count[node_idx]+1.0);
386  const Real add_weight = 1.0/(nodal_data_count[node_idx]+1.0);
387  nodal_data[node_idx] = accumulated_weight*nodal_data[node_idx] + add_weight*geometry_field_data[g];
388  ++nodal_data_count[node_idx];
389  }
390  }
391  }
392 
393  for (Uint n=0; n<nodal_data.size(); ++n)
394  {
395  file << nodal_data[n] << " ";
396  CF3_BREAK_LINE(file,n)
397  }
398  file << "\n";
399 
400  }
401  }
402  else
403  {
404  // field not defined for this zone, so write zeros
405  if (options().value<bool>("cell_centred"))
406  file << nb_elems << "*" << 0.;
407  else
408  file << used_nodes.size() << "*" << 0.;
409  file << "\n";
410  }
411  }
412  var_idx++;
413  }
414  }
415  }
416 
417  file << "\n### connectivity\n\n";
418  // write connectivity
419  const Connectivity& connectivity = elements.geometry_space().connectivity();
420  for (Uint e=0; e<elements.size(); ++e)
421  {
422  if (m_enable_overlap || !elements.is_ghost(e))
423  {
424  if (etype.shape() == GeoShape::POINT)
425  {
426  // these are represented by a FELINESEG, with coalesced nodes
427  Uint const& n = connectivity[e][0];
428  file << zone_node_idx[n] << " "
429  << zone_node_idx[n] << " ";
430  }
431  else
432  {
433  boost_foreach ( Uint n, connectivity[e])
434  {
435  file << zone_node_idx[n] << " ";
436  }
437  }
438  file << "\n";
439  }
440  }
441  file << "\n\n";
442 
443  }
444 }
445 
446 
447 std::string Writer::zone_type(const ElementType& etype) const
448 {
449  if ( etype.shape() == GeoShape::LINE) return "FELINESEG";
450  if ( etype.shape() == GeoShape::TRIAG) return "FETRIANGLE";
451  if ( etype.shape() == GeoShape::QUAD) return "FEQUADRILATERAL";
452  if ( etype.shape() == GeoShape::TETRA) return "FETETRAHEDRON";
453  if ( etype.shape() == GeoShape::PYRAM) return "FEBRICK"; // with coalesced nodes
454  if ( etype.shape() == GeoShape::PRISM) return "FEBRICK"; // with coalesced nodes
455  if ( etype.shape() == GeoShape::HEXA) return "FEBRICK";
456  if ( etype.shape() == GeoShape::POINT) return "FELINESEG"; // with coalesced nodes
457  cf3_assert_desc("should not be here",false);
458  return "INVALID";
459 }
461 
462 #undef CF3_BREAK_LINE
463 
464 } // tecplot
465 } // mesh
466 } // cf3
const ShapeFunction & shape_function() const
Definition: Space.cpp:102
std::string name(ComponentWrapper &self)
virtual void write()
Definition: Writer.cpp:67
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
Helper class to create the Builder and place it in the factory.
Definition: Builder.hpp:212
Space & geometry_space() const
Definition: Entities.hpp:94
virtual const RealMatrix & local_coordinates() const =0
bool continuous() const
Definition: Field.cpp:235
bool m_enable_overlap
If true, writing of overlap will be enabled.
Definition: MeshWriter.hpp:93
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
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
Conversions from and to std::string.
Real e()
Definition of the Unit charge [C].
Definition: Consts.hpp:30
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
Uint size() const
return the number of elements
Definition: Entities.cpp:161
#define cf3_assert_desc(m, a)
Definition: Assertions.hpp:94
virtual std::vector< std::string > get_extensions()
Definition: Writer.cpp:58
Handle< Component > parent() const
Definition: Component.cpp:256
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealVector
Dynamic sized column vector.
Definition: MatrixTypes.hpp:25
GeoShape::Type shape() const
Definition: ElementType.hpp:64
common::ComponentBuilder< tecplot::Writer, MeshWriter, LibTecplot > atecplotWriter_Builder
Definition: Writer.cpp:44
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
boost::proto::terminal< SFOp< CoordinatesOp > >::type const coordinates
std::string zone_type(const ElementType &etype) const
Definition: Writer.cpp:447
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
Handle< Component > handle()
Get a handle to the component.
Definition: Component.hpp:179
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
Space component class.
Definition: Space.hpp:59
#define CF3_BREAK_LINE(f, x)
Definition: Writer.cpp:40
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
std::string shape_name() const
Definition: ElementType.hpp:61
void write_file(std::fstream &file)
Definition: Writer.cpp:92
bool discontinuous() const
Definition: Field.cpp:241
#define FromHere()
Send comments to:
COOLFluiD Web Admin