Skip to content

Commit e842b1e

Browse files
authored
Merge pull request ComputationalRadiationPhysics#2484 from codingS3b/visualizer
Python MPL Visualization modules
2 parents 4cc4858 + 375d3dd commit e842b1e

File tree

11 files changed

+774
-4
lines changed

11 files changed

+774
-4
lines changed

docs/source/usage/plugins/phaseSpace.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ The easiest way is to load the data in Python:
7373
7474
# load data
7575
phase_space = PhaseSpace('/home/axel/runs/foil_001')
76-
e_ps, e_ps_meta = phase_space.get('e', species_filter='all', ps='ypy', iteration=1000)
76+
e_ps, e_ps_meta = phase_space.get('e', species_filter='all', iteration=1000, ps='ypy')
7777
7878
# unit conversion from SI
7979
mu = 1.e6 # meters to microns

lib/python/picongpu/plugins/energy_histogram.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def get_iterations(self, species, species_filter="all"):
101101
dtype=np.uint64).as_matrix()[:, 0]
102102

103103
def get(self, species, species_filter="all", iteration=None,
104-
include_overflow=False):
104+
include_overflow=False, **kwargs):
105105
"""
106106
Get a histogram.
107107

lib/python/picongpu/plugins/phase_space.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ def get_iterations(self, species, species_filter='all', ps=None):
188188

189189
return iterations
190190

191-
def get(self, species, species_filter='all', ps=None, iteration=None):
191+
def get(self, species, species_filter='all', iteration=None, ps=None,
192+
**kwargs):
192193
"""
193194
Get a phase space histogram.
194195

lib/python/picongpu/plugins/plot_mpl/__init__.py

Whitespace-only changes.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"""
2+
This file is part of the PIConGPU.
3+
4+
Copyright 2017-2018 PIConGPU contributors
5+
Authors: Sebastian Starke
6+
License: GPLv3+
7+
"""
8+
9+
import matplotlib.pyplot as plt
10+
11+
12+
class Visualizer(object):
13+
"""
14+
Abstract base class for matplotlib visualizers that implements
15+
the visualization logic.
16+
Classes that derive from this class need to write their own implementations
17+
for the following functions in order to work:
18+
_create_data_reader(self, run_directory)
19+
_create_plt_obj(self, ax)
20+
_update_plt_obj(self)
21+
"""
22+
23+
def __init__(self, run_directory):
24+
"""
25+
Initialize the reader and data as member parameters.
26+
27+
Parameters
28+
----------
29+
run_directory : string
30+
path to the run directory of PIConGPU
31+
(the path before ``simOutput/``)
32+
"""
33+
if run_directory is None:
34+
raise ValueError('The run_directory parameter can not be None!')
35+
36+
self.plt_obj = None
37+
self.data_reader = self._create_data_reader(run_directory)
38+
self.data = None
39+
40+
def _create_data_reader(self, run_directory):
41+
"""
42+
Needs to return an instance of a picongpu data reader
43+
(as defined in the ../plugin directory) which implements
44+
a 'get()' method.
45+
"""
46+
raise NotImplementedError
47+
48+
def _create_plt_obj(self, ax):
49+
"""
50+
Sets 'self.plt_obj' to an instance of a matplotlib.artist.Artist
51+
object (or derived classes) which can be updated
52+
by feeding new data into it.
53+
Only called on the first call for visualization.
54+
55+
Parameters
56+
----------
57+
ax: matplotlib.axes.Axes instance
58+
"""
59+
raise NotImplementedError
60+
61+
def _update_plt_obj(self):
62+
"""
63+
Take the 'self.data' member, interpret it and feed it into the
64+
'self.plt_obj'.
65+
"""
66+
raise NotImplementedError
67+
68+
def _ax_or_gca(self, ax):
69+
"""
70+
Returns the passed ax if it is not None or the current
71+
matplotlib axes object otherwise.
72+
73+
Parameters
74+
----------
75+
ax: None or matplotlib.axes.Axes instance
76+
Returns
77+
-------
78+
A matplotlib.axes.Axes instance
79+
"""
80+
81+
return ax or plt.gca()
82+
83+
def visualize(self, ax=None, **kwargs):
84+
"""
85+
1. Creates the 'plt_obj' if it does not exist
86+
2. Fills the 'data' parameter by using the reader
87+
3. Updates the 'plt_obj' with the new data.
88+
"""
89+
if ax is None:
90+
raise ValueError("A matplotlib axes object needs to be passed!")
91+
92+
self.data = self.data_reader.get(**kwargs)
93+
if self.plt_obj is None:
94+
self._create_plt_obj(ax)
95+
else:
96+
self._update_plt_obj()
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"""
2+
This file is part of the PIConGPU.
3+
4+
Copyright 2017-2018 PIConGPU contributors
5+
Authors: Sebastian Starke
6+
License: GPLv3+
7+
"""
8+
9+
from picongpu.plugins.energy_histogram import EnergyHistogram
10+
from picongpu.plugins.plot_mpl.base_visualizer import Visualizer as\
11+
BaseVisualizer, plt
12+
13+
14+
class Visualizer(BaseVisualizer):
15+
"""
16+
Class for creation of histogram plots on a logscaled y-axis.
17+
"""
18+
19+
def __init__(self, run_directory):
20+
"""
21+
Parameters
22+
----------
23+
run_directory : string
24+
path to the run directory of PIConGPU
25+
(the path before ``simOutput/``)
26+
"""
27+
super(Visualizer, self).__init__(run_directory)
28+
29+
def _create_data_reader(self, run_directory):
30+
"""
31+
Implementation of base class function.
32+
"""
33+
return EnergyHistogram(run_directory)
34+
35+
def _create_plt_obj(self, ax):
36+
"""
37+
Implementation of base class function.
38+
Turns 'self.plt_obj' into a matplotlib.pyplot.plot object.
39+
"""
40+
bins, counts = self.data
41+
self.plt_obj = ax.semilogy(bins, counts, nonposy='clip')[0]
42+
43+
def _update_plt_obj(self):
44+
"""
45+
Implementation of base class function.
46+
"""
47+
bins, counts = self.data
48+
self.plt_obj.set_data(bins, counts)
49+
50+
def visualize(self, ax=None, **kwargs):
51+
"""
52+
Creates a semilogy plot on the provided axes object for
53+
the data of the given iteration using matpotlib.
54+
55+
Parameters
56+
----------
57+
iteration: int
58+
the iteration number for which data will be plotted.
59+
ax: matplotlib axes object
60+
the part of the figure where this plot will be shown.
61+
kwargs: dictionary with further keyword arguments, valid are:
62+
species: string
63+
short name of the particle species, e.g. 'e' for electrons
64+
(defined in ``speciesDefinition.param``)
65+
iteration: int
66+
number of the iteration
67+
species_filter: string
68+
name of the particle species filter, default is 'all'
69+
(defined in ``particleFilters.param``)
70+
71+
"""
72+
ax = self._ax_or_gca(ax)
73+
# this already throws error if no species or iteration in kwargs
74+
super(Visualizer, self).visualize(ax, **kwargs)
75+
iteration = kwargs.get('iteration')
76+
species = kwargs.get('species')
77+
species_filter = kwargs.get('species_filter', 'all')
78+
79+
if iteration is None or species is None:
80+
raise ValueError("Iteration and species have to be provided as\
81+
keyword arguments!")
82+
83+
ax.set_xlabel('Energy [keV]')
84+
ax.set_ylabel('Count')
85+
ax.set_title('Energy Histogram for species ' +
86+
species + ', filter = ' + species_filter +
87+
', iteration ' + str(iteration))
88+
89+
90+
if __name__ == '__main__':
91+
92+
def main():
93+
import sys
94+
import getopt
95+
96+
def usage():
97+
print("usage:")
98+
print(
99+
"python", sys.argv[0],
100+
"-p <path to run_directory> -i <iteration>"
101+
" -s <particle species> -f <species_filter>")
102+
103+
path = None
104+
iteration = None
105+
species = None
106+
filtr = None
107+
108+
try:
109+
opts, args = getopt.getopt(sys.argv[1:], "hp:i:s:f:", [
110+
"help", "path", "iteration", "species", "filter"])
111+
except getopt.GetoptError as err:
112+
print(err)
113+
usage()
114+
sys.exit(2)
115+
116+
for opt, arg in opts:
117+
if opt in ["-h", "--help"]:
118+
usage()
119+
sys.exit()
120+
elif opt in ["-p", "--path"]:
121+
path = arg
122+
elif opt in ["-i", "--iteration"]:
123+
iteration = int(arg)
124+
elif opt in ["-s", "--species"]:
125+
species = arg
126+
elif opt in ["-f", "--filter"]:
127+
filtr = arg
128+
129+
# check that we got all args that we need
130+
if path is None or iteration is None:
131+
print("Path to 'run' directory and iteration have to be provided!")
132+
usage()
133+
sys.exit(2)
134+
if species is None:
135+
species = 'e'
136+
print("Particle species was not given, will use", species)
137+
if filtr is None:
138+
filtr = 'all'
139+
print("Species filter was not given, will use", filtr)
140+
141+
fig, ax = plt.subplots(1, 1)
142+
Visualizer(path).visualize(ax, iteration=iteration, species=species,
143+
species_filter=filtr)
144+
plt.show()
145+
146+
main()

0 commit comments

Comments
 (0)