Peano
Loading...
Searching...
No Matches
PlotParticlesInVTKFormat.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3from peano4.solversteps.ActionSet import ActionSet
4
5
6import jinja2
7
8
10 """
11
12 For constructor's time_stamp_evaluation argument.
13
14 """
15
16 NoMetaFile = "no-meta-file"
17
18 """
19
20 For constructor's time_stamp_evaluation argument.
21
22 """
23 CountTimeSteps = "count-time-steps"
24
25 """
26
27 By default, I plot the point particles (obviously) and drop their
28 coordinates as vector, too. I also plot the search radius which
29 is a simple scalar. I often use it to colour-code or as radius
30 of the rendered sphere.
31
32 Finally, I do render the associativity. This is one vector per
33 point that points towards the vertex the object belongs to. To
34 visualise it, add a Glyph filter and select association as
35 orientation array. Make association also the scale array and
36 scale by magnitude.
37
38 """
39
41 self,
42 filename,
43 particle_set,
44 time_stamp_evaluation=NoMetaFile,
45 additional_includes="",
46 ):
47 """
48 Plot only the grid structure
49
50 :Attibutes:
51
52 filename: String
53 Name of the output file.
54
55 particle: ParticleSet
56 I take this as particle set and I assume that it yields a C++
57 container which I can traverse.
58
59 time_stamp_evaluation: String yielding a C++ double
60 Pass in prefined constants to use default behaviour.
61
62 """
63 super(PlotParticlesInVTKFormat, self).__init__(descend_invocation_order=1, parallel=False)
64
65 self.d = {}
66 self.d["FILENAME"] = filename
67 self.d["PARTICLE"] = particle_set.particle_model.name
68 self.d["PARTICLES_CONTAINER"] = particle_set.name
69 self.d["WRITE_BINARY"] = "false"
70 self.d["ATTRIBUTE_WRITER_NULL_INITIALISERS"] = ""
71 self.d["ATTRIBUTE_WRITER_CLOSES"] = ""
72 self.d["ATTRIBUTE_WRITER_DELETES"] = ""
73 self.d["ATTRIBUTE_WRITER_INITIALISERS"] = ""
74 self.d["ATTRIBUTE_WRITER_PLOT_CALLS"] = ""
75 self.d["TIMESTAMP"] = time_stamp_evaluation
76
78
79 self.additional_includes = additional_includes
80
81 __Template_Constructor = jinja2.Template(
82 """
83 _writer = nullptr;
84 _positionWriter = nullptr;
85 _searchRadiusWriter = nullptr;
86 _associationWriter = nullptr;
87 {{ATTRIBUTE_WRITER_NULL_INITIALISERS}}
88 _treeNumber = treeNumber;
89
90 // An MPI lock (critical section) would be important!
91
92 logDebug( "PlotGrid2PlotGridInPeanoBlockFormat1()", "created tree instance for " << treeNumber );
93"""
94 )
95
96 def add_attribute_to_plot(self, attribute, cardinality=1, accessor=None):
97 """
98
99 Add an attribute to the plotter
100
101 You have to ensure that each attribute is added at most once.
102
103
104 ## Type casts for non-floating point types
105
106 The plotter supports only floating point data. If you have attributes that are
107 not of floating point type, then you have to convert them into floating point
108 data before they are dumped into VTK. For this, the routine offers the accessor
109 attribute. As long as it equals None, we assume that there is a pointer p pointing
110 to the particle, and that we can use getXXXX() to access the attribute data. The
111 XXXX is the name of the attribute with the first letter written uppercase. This
112 is how Peano 4 writes down accessors (using DaStGen - but that's a different story
113 how and why we use certain code generator conventions).
114
115 You can however inject any other accessor expression (using the pointer p) to
116 read out particle data. If your particle data is for example a vector over
117 integers, you might want to hand in
118
119 tarch::la::convertScalar<double>(p->getXXXX())
120
121 which converts the data into a proper format.
122
123
124 ## Arguments
125
126 attribute: Attribute
127 The actual attribute that we have to plot.
128
129 cardinality: Integer
130 The cardinality of the attribute. This is 1 for a scalar value, 2 for a 2d vector,
131 and so forth. We support arbitrary cardinalities, but the cardinality hsa to match
132 attribute.
133
134 accessor: String or None
135 If this term is None, then we use getXXX() constructs as they are generated by
136 DaStGen by default. If you hand in something not equal to None, then we use this
137 particular string to access a field of a pointer p, i.e. we use
138
139 p->accessor
140
141 to get the data out of the particle.
142
143 """
144 assert cardinality > 0, "cardinality has to be greater than 0"
145
146 self._attributes_to_plot.append(attribute)
147 writer_name = f"_{attribute._name}Writer"
148 delim = "\n "
149 if accessor != None:
150 accessor_name = accessor
151 elif cardinality <= 3:
152 accessor_name = (
153 "p->get" + attribute._name[0].title() + attribute._name[1:] + "()"
154 )
155 else:
156 accessor_name = (
157 "p->get"
158 + attribute._name[0].title()
159 + attribute._name[1:]
160 + "().data()"
161 )
162
163 self.d[
164 "ATTRIBUTE_WRITER_NULL_INITIALISERS"
165 ] += f"{delim}{writer_name} = nullptr;"
166 self.d["ATTRIBUTE_WRITER_CLOSES"] += f"{delim}{writer_name}->close();"
167 self.d["ATTRIBUTE_WRITER_DELETES"] += f"{delim}delete {writer_name};"
168 self.d[
169 "ATTRIBUTE_WRITER_INITIALISERS"
170 ] += f'{delim}{writer_name} = _writer->createPointDataWriter( "{attribute._name}", {cardinality} );'
171 if cardinality <= 3:
172 self.d[
173 "ATTRIBUTE_WRITER_PLOT_CALLS"
174 ] += f"{delim} {writer_name}->plot(particleNumber,{accessor_name});"
175 else:
176 self.d[
177 "ATTRIBUTE_WRITER_PLOT_CALLS"
178 ] += f"{delim} {writer_name}->plot(particleNumber,{accessor_name},{cardinality});"
179
181 return self.__Template_Constructor.render(**self.d)
182
184 return ""
185
187 return " return std::vector< peano4::grid::GridControlEvent >();\n"
188
190 return __name__.replace(".py", "").replace(".", "_")
191
193 return False
194
195 __Template_TouchVertexFirstTime = jinja2.Template(
196 """
197 assertion( _positionWriter!=nullptr );
198 for (auto* p: fineGridVertex{{PARTICLES_CONTAINER}}) {
199 if (
200 p->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local
201 ) {
202 int particleNumber = _writer->plotPoint(p->getX());
203 _positionWriter->plot(particleNumber,p->getX());
204 _searchRadiusWriter->plot(particleNumber,p->getSearchRadius());
205 _associationWriter->plot(particleNumber,marker.x()-p->getX());
206 {{ATTRIBUTE_WRITER_PLOT_CALLS}}
207 }
208 }
209"""
210 )
211
212 __Template_BeginTraversal = jinja2.Template(
213 """
214 tarch::mpi::Lock lock( _semaphore );
215
216 static int counter = -1;
217 counter++;
218
219 std::ostringstream snapshotFileName;
220 snapshotFileName << "{{FILENAME}}-" << counter;
221
222 if (tarch::mpi::Rank::getInstance().getNumberOfRanks()>1 ) {
223 snapshotFileName << "-rank-" << tarch::mpi::Rank::getInstance().getRank();
224 }
225
226 {% if TIMESTAMP==\""""
227 + NoMetaFile
228 + """\" %}
229 _writer = new tarch::plotter::pointdata::vtk::VTKWriter(
230 false, snapshotFileName.str(), "{{FILENAME}}",
231 tarch::plotter::PVDTimeSeriesWriter::IndexFileMode::NoIndexFile,
232 0.0
233 );
234 {% elif TIMESTAMP==\""""
235 + CountTimeSteps
236 + """\" %}
237 _writer = new tarch::plotter::pointdata::vtk::VTKWriter(
238 false, snapshotFileName.str(), "{{FILENAME}}",
239 tarch::plotter::PVDTimeSeriesWriter::IndexFileMode::AppendNewData,
240 counter / peano4::parallel::SpacetreeSet::getInstance().getLocalSpacetrees().size()
241 );
242 {% else %}
243 _writer = new tarch::plotter::pointdata::vtk::VTKWriter(
244 false, snapshotFileName.str(), "{{FILENAME}}",
245 tarch::plotter::PVDTimeSeriesWriter::IndexFileMode::AppendNewData,
246 {{TIMESTAMP}}
247 );
248 {% endif %}
249
250 _positionWriter = _writer->createPointDataWriter( "x", 3 );
251 _searchRadiusWriter = _writer->createPointDataWriter( "search-radius", 1 );
252 _associationWriter = _writer->createPointDataWriter( "association", 3 );
253 {{ATTRIBUTE_WRITER_INITIALISERS}}
254"""
255 )
256
257 __Template_EndTraversal = jinja2.Template(
258 """
259 assertion(_positionWriter!=nullptr);
260
261 _positionWriter->close();
262 _searchRadiusWriter->close();
263 _associationWriter->close();
264 {{ATTRIBUTE_WRITER_CLOSES}}
265 _writer->writeToFile();
266
267 delete _positionWriter;
268 delete _searchRadiusWriter;
269 delete _associationWriter;
270 {{ATTRIBUTE_WRITER_DELETES}}
271 delete _writer;
272
273 _positionWriter = nullptr;
274 _searchRadiusWriter = nullptr;
275 _associationWriter = nullptr;
276 {{ATTRIBUTE_WRITER_NULL_INITIALISERS}}
277 _writer = nullptr;
278"""
279 )
280
281 def get_body_of_operation(self, operation_name):
282 result = "\n"
283 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME:
284 result = self.__Template_TouchVertexFirstTime.render(**self.d)
285 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
286 result = self.__Template_BeginTraversal.render(**self.d)
287 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
288 result = self.__Template_EndTraversal.render(**self.d)
289 return result
290
292 delim = "\n "
293 datatype = "tarch::plotter::pointdata::PointWriter::PointDataWriter*"
294 return delim.join(
295 f"{datatype} _{attr._name}Writer;" for attr in self._attributes_to_plot
296 )
297
298 def get_attributes(self):
299 return f"""
300 static tarch::mpi::BooleanSemaphore _semaphore;
301
302 int _treeNumber;
303
304 tarch::plotter::pointdata::vtk::VTKWriter* _writer;
305 tarch::plotter::pointdata::PointWriter::PointDataWriter* _positionWriter;
306 tarch::plotter::pointdata::PointWriter::PointDataWriter* _searchRadiusWriter;
307 tarch::plotter::pointdata::PointWriter::PointDataWriter* _associationWriter;
308 {self._get_attribute_writer_declarations()}
309"""
310
311 def get_includes(self):
312 return (
313 """
314#include "tarch/plotter/pointdata/vtk/VTKWriter.h"
315#include "tarch/multicore/Lock.h"
316#include "tarch/multicore/BooleanSemaphore.h"
317#include "tarch/mpi/Lock.h"
318#include "tarch/mpi/BooleanSemaphore.h"
319#include "peano4/parallel/SpacetreeSet.h"
320#include "../vertexdata/"""
321 + self.d["PARTICLES_CONTAINER"]
322 + """.h"
323#include "../globaldata/"""
324 + self.d["PARTICLE"]
325 + """.h"
326"""
328 )
329
330 def get_static_initialisations(self, full_qualified_classname):
331 return (
332 """
333tarch::mpi::BooleanSemaphore """
334 + full_qualified_classname
335 + """::_semaphore;
336"""
337 )
Action set (reactions to events)
Definition ActionSet.py:6
__init__(self, filename, particle_set, time_stamp_evaluation=NoMetaFile, additional_includes="")
Plot only the grid structure.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
add_attribute_to_plot(self, attribute, cardinality=1, accessor=None)
Add an attribute to the plotter.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.