3 Represents a flow profile, as created by `OpenMPCD::FlowProfile`.
23 Adds the flow profile data in the given `rundir` to the data gathered so
28 raise Exception(
"Cannot currently concatenate two multi-block runs")
39 if os.path.isfile(rundir +
'/flowProfile.data.bz2'):
41 tmpfile = bz2.BZ2File(rundir +
'/flowProfile.data.bz2')
42 elif os.path.isfile(rundir +
'/flowProfile.data'):
43 tmpfile = open(rundir +
'/flowProfile.data',
'r')
45 raise Exception(
"Invalid rundir: " + rundir)
56 columns = line.split()
57 slice_ = [ int(i)
for i
in columns[0:3] ]
58 mean = [ float(i)
for i
in columns[3:6] ]
59 standardDeviation = [ float(i)
for i
in columns [6:9] ]
60 sampleSize = int(columns[9])
70 self, standardError = 1, theory = True, shift = True):
72 Returns a `matplotlib.axes.Axes` object that contains a plot of the
73 flow profile, with the horizontal axis showing the simulation `y`
74 coordinate, and the vertical axis showing the average flow velocity in
75 `x` direction (along with its standard deviation) at that point.
77 @param[in] standardError
78 Include a shaded region around the mean that corresponds to
79 `standardError` times the standard error. Set to `0` to omit
80 this shaded region altogether.
82 Set to `True` to also include a plot of the theoretical shear
85 Set to `True` to shift the data points along the `y`
86 direction in such a way that a data point lies not at the
87 beginning of the `y` segment it describes, but rather at its
91 import matplotlib.figure
93 figure = matplotlib.figure.Figure()
94 axes = figure.add_subplot(1, 1, 1)
102 [velocity[velocityIndex].getSampleMean()
103 for velocity
in data.values()]
104 _line, = axes.plot(data.keys(), values)
106 legendLabels.append(
"Flow Profile")
111 _line, = axes.plot(theoryData.keys(), theoryData.values())
113 legendLabels.append(
"Theory")
115 if standardError != 0:
116 if standardError < 0:
122 values = numpy.array(values)
123 sqrt_n = math.sqrt(velocity[velocityIndex].getSampleSize())
126 [velocity[velocityIndex].getSampleStandardDeviation() /
128 for velocity
in data.values()])
132 values - standardError * errors,
133 values + standardError * errors,
136 axes.legend(lines, legendLabels)
143 Returns the flow profile as a function of `y`.
145 The value returned is a dictionary, with the keys being `y` coordinates
146 in simulation space, and the values being a lists of three
147 `OnTheFlyStatistics` instances, for the flow velocities along the `x`,
148 `y`, and `z` direction, respectively.
151 Set to `True` to shift the data points along the `y`
152 direction in such a way that a data point lies not at the
153 beginning of the `y` segment it describes, but rather at its
157 from .OnTheFlyStatistics
import OnTheFlyStatistics
158 from collections
import OrderedDict
162 for _, xval
in self.
_points.items():
163 for yIndex, yval
in xval.items():
167 if yCoord
not in ret:
170 OnTheFlyStatistics(),
171 OnTheFlyStatistics(),
175 for _, zval
in yval.items():
176 ret[yCoord][0].mergeSample(zval[0])
177 ret[yCoord][1].mergeSample(zval[1])
178 ret[yCoord][2].mergeSample(zval[2])
185 Returns a list of three `OnTheFlyStatistics` objects that combine, one
186 for each of the three Cartesian coordinates, that combines all samples
187 of particle velocities across the simulation volume.
190 from .OnTheFlyStatistics
import OnTheFlyStatistics
192 ret = [OnTheFlyStatistics(), OnTheFlyStatistics(), OnTheFlyStatistics()]
195 for yval
in xval.values():
196 for zval
in yval.values():
198 ret[i].mergeSample(zval[i])
205 self, shearRate = None, shift = True):
207 Returns the analytic flow profile of a shear flow as a function of `y`.
209 The shear flow is assumed to have the flow direction along the positive
210 `x` direction, and the gradient direction is assumed to be the `y`
213 The value returned is a dictionary, with the keys being `y` coordinates
214 in simulation space, and the values being the mean flow speed along the
218 Sets the shear rate. If `None`, and a run has been added
219 which does specify a shear rate, that value is assumed.
220 Otherwise, an exception is thrown.
223 Set to `True` to shift the data points along the `y`
224 direction in such a way that a data point lies not at the
225 beginning of the `y` segment it describes, but rather at its
229 if shearRate
is None:
230 if not hasattr(self,
"_shearRate"):
234 if not isinstance(shearRate, float):
237 if not hasattr(self,
"_simBoxSizeY"):
241 if not hasattr(self,
"_linearSubdivisions"):
245 from collections
import OrderedDict
249 maxYIndex = simBoxSizeY * linearSubdivisions - 1
250 for yIndex
in range(0, maxYIndex + 1):
251 yCoord = float(yIndex) / linearSubdivisions
253 yCoord += 0.5 / linearSubdivisions
255 v_x = (yCoord - 0.5 * simBoxSizeY) * shearRate
261 def showVectorFieldGUI(self):
262 import matplotlib.pyplot
263 from .PlotTools
import DiscreteSliderWidget
266 fig, ax = matplotlib.pyplot.subplots()
267 ax.set_title(
"Flow Profile")
270 ax.grid(
True, which =
'both')
271 matplotlib.pyplot.xlabel(
"x")
272 matplotlib.pyplot.ylabel(
"y")
275 matplotlib.pyplot.subplots_adjust(left = 0.1, bottom = 0.25)
278 currentParameters = \
284 timeAxes = matplotlib.pyplot.axes([0.1, 0.1, 0.8, 0.03])
286 DiscreteSliderWidget(
287 timeAxes,
"Output Block",
288 currentParameters[
'outputBlockID'], len(self.
_outputBlocks) - 1,
289 valinit = 0, valfmt =
'%0.0f')
291 zAxes = matplotlib.pyplot.axes([0.1, 0.05, 0.8, 0.03])
293 DiscreteSliderWidget(
296 valinit = 0, valfmt =
'%0.0f')
302 X, Y = numpy.meshgrid(xPoints, yPoints)
307 outputBlock = self.
_outputBlocks[currentParameters[
'outputBlockID']]
312 z = currentParameters[
'z']
315 v = outputBlock[x][y][z]
316 v = [v[i].getSampleMean()
for i
in range(0, 3)]
328 quiverProxy[0].set_UVC(U, V, C)
330 quiverProxy.append(ax.quiver(X, Y, U, V, C, units =
'width'))
332 fig.canvas.draw_idle()
334 def updateData_time(newOutputBlockID):
335 currentParameters[
'outputBlockID'] = newOutputBlockID
338 def updateData_z(newZ):
339 currentParameters[
'z'] = newZ
342 timeSlider.on_changed(updateData_time)
343 zSlider.on_changed(updateData_z)
348 mng = matplotlib.pyplot.get_current_fig_manager()
349 mng.resize(*mng.window.maxsize())
350 matplotlib.pyplot.show()
353 def _setConfigOrCheckCompatibility(self, rundir):
355 Reads the configuration in the given `rundir`, and either sets it to be
356 the reference configuration if this is the first `rundir` this instance
357 is supplied, or otherwise verifies that the configurations are
361 from .Configuration
import Configuration
362 config = Configuration(rundir)
364 if not hasattr(self,
"_linearSubdivisions"):
367 "_linearSubdivisions",
"_shearRate",
368 "_simBoxSizeX",
"_simBoxSizeY",
"_simBoxSizeZ",
370 for attribute
in attributeList:
371 if hasattr(self, attribute):
376 if "instrumentation.flowProfile.cellSubdivision.y" in config:
377 value = config[
"instrumentation.flowProfile.cellSubdivision.y"]
380 if "boundaryConditions.LeesEdwards.shearRate" in config:
382 config[
"boundaryConditions.LeesEdwards.shearRate"]
392 linearSubdivisions = 1
393 if "instrumentation.flowProfile.cellSubdivision.y" in config:
394 linearSubdivisions = \
395 config[
"instrumentation.flowProfile.cellSubdivision.y"]
401 if "boundaryConditions.LeesEdwards.shearRate" in config:
403 config[
"boundaryConditions.LeesEdwards.shearRate"]
407 if self.
_simBoxSizeY != config[
"mpc.simulationBoxSize.y"]:
412 def _addSampleToPoint(self, slice_, means, standardDeviations, sampleSize):
414 Adds the data given (`means`, `standardDeviations`, and `sampleSize`) to
415 the point specified by the slice coordinates in `slice_`, which is
416 assumed to be a list of three coordinates (each corresponding to the
417 simulation coordinates after being multiplied with the appropriate
418 `instrumentation.cellSubdivision` configuration value).
420 If no data exists yet for that point, a new instance of
421 `OnTheFlyStatistics` is created.
424 from .OnTheFlyStatistics
import OnTheFlyStatistics
425 from collections
import OrderedDict
429 self.
_points[x] = OrderedDict()
431 self.
_points[x][y] = OrderedDict()
432 if z
not in self.
_points[x][y]:
434 self.
_points[x][y][z].append(OnTheFlyStatistics())
435 self.
_points[x][y][z].append(OnTheFlyStatistics())
436 self.
_points[x][y][z].append(OnTheFlyStatistics())
439 OnTheFlyStatistics(means[0], standardDeviations[0] ** 2, sampleSize)
441 OnTheFlyStatistics(means[1], standardDeviations[1] ** 2, sampleSize)
443 OnTheFlyStatistics(means[2], standardDeviations[2] ** 2, sampleSize)
445 self.
_points[x][y][z][0].mergeSample(newSampleX)
446 self.
_points[x][y][z][1].mergeSample(newSampleY)
447 self.
_points[x][y][z][2].mergeSample(newSampleZ)