Commit d3f18aaa authored by Dion Haefner's avatar Dion Haefner

fixed python tools - also, dorie plot works way better now

parent ff94bcf2
...@@ -39,7 +39,7 @@ initialize_folder() ...@@ -39,7 +39,7 @@ initialize_folder()
plot_vtk() plot_vtk()
{ {
$DORIE_PYTHON plot_vtk.py --vtk $1 --var $2 $DORIE_PYTHON plot_vtk.py -f $1 --var $2
} }
pf_from_file() pf_from_file()
......
...@@ -77,7 +77,7 @@ namespace Dune { ...@@ -77,7 +77,7 @@ namespace Dune {
std::cout << "h5_Write: " << filename << std::endl; std::cout << "h5_Write: " << filename << std::endl;
UINT dim = local_count.size(); UINT dim = global_dim.size();
//std::cout << std::endl << "h5_Write: dim = " << dim << std::endl; //std::cout << std::endl << "h5_Write: dim = " << dim << std::endl;
std::cout << "h5_Write: groupname = " << groupname << std::endl; std::cout << "h5_Write: groupname = " << groupname << std::endl;
...@@ -137,34 +137,6 @@ namespace Dune { ...@@ -137,34 +137,6 @@ namespace Dune {
//std::cout << "h5_Write: plist_id created." << std::endl; //std::cout << "h5_Write: plist_id created." << std::endl;
herr_t status;
hsize_t maxnchunks = 1;
hsize_t chunk_dims[ dim ];
for(UINT i=0;i<dim;i++)
chunk_dims[i] = (hsize_t) 1;
status = H5Pset_chunk(
plist_id
, dim // must be == rank of the dataset
, chunk_dims // The values of the check_dims array define the size of the chunks to store the dataset's raw data. The unit of measure for check_dims values is dataset elements.
);
assert( status > -1 );
//std::cout << "h5_Write: H5Pset_chunk() o.k." << std::endl;
status = H5Pset_shuffle( plist_id ); // Sets the shuffle filter, H5Z_FILTER_SHUFFLE, in the dataset creation property list. This re-orders data to simplify compression.
assert( status > -1 );
//std::cout << "h5_Write: H5Pset_shuffle() o.k." << std::endl;
status = H5Pset_deflate( plist_id, 1 ); // Sets deflate (GNU gzip) compression method and compression level. ( 0 < level < 9, lower = faster, but less compression )
assert( status > -1 );
//std::cout << "h5_Write: H5Pset_deflate() o.k." << std::endl;
/* Create the dataset. */ /* Create the dataset. */
hid_t dataset_id = H5Dcreate1( file_id, hid_t dataset_id = H5Dcreate1( file_id,
...@@ -178,7 +150,7 @@ namespace Dune { ...@@ -178,7 +150,7 @@ namespace Dune {
/* Write the dataset. */ /* Write the dataset. */
status = H5Dwrite( // Writes raw data from a buffer to a dataset. herr_t status = H5Dwrite( // Writes raw data from a buffer to a dataset.
dataset_id // dataset identifier dataset_id // dataset identifier
, H5T_NATIVE_DOUBLE // memory datatype id , H5T_NATIVE_DOUBLE // memory datatype id
, memspace_id // specifies the memory dataspace and the selection within it , memspace_id // specifies the memory dataspace and the selection within it
......
...@@ -169,7 +169,7 @@ void RichardsSolver (GridType grid, GV& gv, ...@@ -169,7 +169,7 @@ void RichardsSolver (GridType grid, GV& gv,
try{ // VTK Plotter has very bad exception handling try{ // VTK Plotter has very bad exception handling
RF t = CCon.getTime(); RF t = CCon.getTime();
if(asciiOutput) vtkwriter.write(t,Dune::VTK::ascii); if(asciiOutput) vtkwriter.write(t,Dune::VTK::ascii);
else vtkwriter.write(t,Dune::VTK::appendedraw); else vtkwriter.write(t,Dune::VTK::base64);
} }
catch(...){ catch(...){
DUNE_THROW(Dune::IOError,"Cannot write VTK output!"); DUNE_THROW(Dune::IOError,"Cannot write VTK output!");
...@@ -268,7 +268,7 @@ void RichardsSolver (GridType grid, GV& gv, ...@@ -268,7 +268,7 @@ void RichardsSolver (GridType grid, GV& gv,
try{ // VTK Plotter has very bad exception handling try{ // VTK Plotter has very bad exception handling
if(asciiOutput) vtkwriter.write(t,Dune::VTK::ascii); if(asciiOutput) vtkwriter.write(t,Dune::VTK::ascii);
else vtkwriter.write(t,Dune::VTK::appendedraw); else vtkwriter.write(t,Dune::VTK::base64);
} }
catch(...){ catch(...){
DUNE_THROW(Dune::IOError,"Cannot write VTK output!"); DUNE_THROW(Dune::IOError,"Cannot write VTK output!");
......
try: # Python 3.x from __future__ import absolute_import
import configparser
except ImportError: # Python 2.x import configparser
import ConfigParser as configparser
def add_section_header(properties_file, header_name): def add_section_header(properties_file, header_name):
# configparser.ConfigParser requires at least one section header # configparser.ConfigParser requires at least one section header
...@@ -10,7 +9,7 @@ def add_section_header(properties_file, header_name): ...@@ -10,7 +9,7 @@ def add_section_header(properties_file, header_name):
yield line yield line
def cp(path): def cp(path):
f = open(path) with open(path) as f:
config = configparser.ConfigParser() config = configparser.RawConfigParser()
config.read_file(add_section_header(f, 'nosection'), source=path) config.read_file(add_section_header(f, "nosection"), path)
return config return config
...@@ -12,7 +12,7 @@ from dorie.parfield import configparser ...@@ -12,7 +12,7 @@ from dorie.parfield import configparser
from dorie.parfield.parameterization import parameterizations from dorie.parfield.parameterization import parameterizations
from dorie.utilities.text_to_bool import text_to_bool from dorie.utilities.text_to_bool import text_to_bool
class BaseConverter: class BaseConverter(object):
""" """
Base class for all parameter field generator modules. Implements the writing Base class for all parameter field generator modules. Implements the writing
of the parameter field to an H5 file, and supplies some utilities. of the parameter field to an H5 file, and supplies some utilities.
......
class Parameterization: class Parameterization(object):
""" """
Base class providing an interface for defining a parameterization (basically Base class providing an interface for defining a parameterization (basically
just a set of possible parameter names, and their associated values). just a set of possible parameter names, and their associated values).
......
h5py==2.6.0 h5py
Pillow==3.1.2 Pillow
configparser
...@@ -61,4 +61,5 @@ if __name__ == "__main__": ...@@ -61,4 +61,5 @@ if __name__ == "__main__":
print(" {0}: {1}".format(w.category.__name__,w.message)) print(" {0}: {1}".format(w.category.__name__,w.message))
print("Parameter field generator exited successfully with ({0}) warning(s) and ({1}) error(s)".format(len(warn),0)) print("Parameter field generator exited successfully with ({0}) warning(s) and ({1}) error(s)".format(len(warn),0))
except Exception as e: except Exception as e:
raise pfgerror.PFGError("Parameter field generator failed with ({0}) warning(s) and ({1}) error(s)".format(len(warn),1)) print("Parameter field generator failed with ({0}) warning(s) and ({1}) error(s)".format(len(warn),1))
raise
...@@ -61,4 +61,5 @@ if __name__ == "__main__": ...@@ -61,4 +61,5 @@ if __name__ == "__main__":
print(" {0}: {1}".format(w.category.__name__,w.message)) print(" {0}: {1}".format(w.category.__name__,w.message))
print("Parameter field generator exited successfully with ({0}) warning(s) and ({1}) error(s)".format(len(warn),0)) print("Parameter field generator exited successfully with ({0}) warning(s) and ({1}) error(s)".format(len(warn),0))
except Exception as e: except Exception as e:
raise pfgerror.PFGError("Parameter field generator failed with ({0}) warning(s) and ({1}) error(s)".format(len(warn),1)) print("Parameter field generator failed with ({0}) warning(s) and ({1}) error(s)".format(len(warn),1))
raise
...@@ -2,35 +2,12 @@ import os ...@@ -2,35 +2,12 @@ import os
import sys import sys
import warnings import warnings
import argparse import argparse
import traceback
from dorie.parscraper import readers, writers, match_parameters from dorie.parscraper import readers, writers, match_parameters
from dorie.parscraper.warnings import OutputWarning from dorie.parscraper.warnings import OutputWarning
def scrape(xml_file,source_folder,out,css=None,source_url=None): def scrape(xml_file,source_folder,out,css=None,debug=False):
"""
Main wrapper, doing most of the work in the parameter scraper.
This function calls the :mod:`XML reader <dorie.parscraper.readers.xml>`,
iterates over all source files in the given folder and calls the
:mod:`source scraper <dorie.parscraper.readers.source>` on each of them.
The output of the two readers is the passed to
:mod:`the matching function <dorie.parsraper.match_parameters>`.
For each given output format, the appropriate :mod:`writer <dorie.parscraper.writers>`
(must be the of the same name as the output file extension) is executed.
:param str xml_file: Path to the XML file holding parameter meta-information
:param str source_folder: The C++ source folder to scrape
:param array_like out: Output file(s)
:param str css: Path to a CSS file to include into HTML output (optional)
:param str source_url: Format string containing path to source files when creating \
links (optional, default: ``source_folder/\{filename\}``). May contain \{filename\} and \{line\} that are substituted \
by the file name and line number, respectively.
:raises Exception: In case the ini writer fails
:raises OutputWarning: In case any other writer fails
"""
# PARSE XML FILE # PARSE XML FILE
if os.path.isfile(xml_file): if os.path.isfile(xml_file):
xml_parameters = readers.xml.parse(xml_file) xml_parameters = readers.xml.parse(xml_file)
...@@ -57,23 +34,21 @@ def scrape(xml_file,source_folder,out,css=None,source_url=None): ...@@ -57,23 +34,21 @@ def scrape(xml_file,source_folder,out,css=None,source_url=None):
# MATCH XML AND SCRAPED PARAMETERS # MATCH XML AND SCRAPED PARAMETERS
matched_parameters = match_parameters.match(xml_parameters,source_parameters,source_folder) matched_parameters = match_parameters.match(xml_parameters,source_parameters,source_folder)
# SET LINK PATH
if not source_url is None:
path_format = source_url
else:
path_format = "file://" + source_folder + "{filename}"
# CALL OUTPUT SCRIPTS # CALL OUTPUT SCRIPTS
for o in out: for o in out:
file_suffix = o.split(".")[-1] file_suffix = o.split(".")[-1]
if hasattr(writers,file_suffix): if hasattr(writers,file_suffix):
writer = getattr(writers,file_suffix) writer = getattr(writers,file_suffix)
try: try:
writer.write(matched_parameters,o,path_format=path_format,css=css) writer.write(matched_parameters,o,source_folder,css=css)
except BaseException as e: except BaseException as e:
if file_suffix == "ini": if file_suffix == "ini":
raise raise
else: else:
warnings.warn("Output failed for file {0} with error:\n{1}".format(o,repr(e)), OutputWarning) warnings.warn("Output failed for file {0} with error:\n{1}".format(o,repr(e)), OutputWarning)
if debug:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
else: else:
warnings.warn("Unknown output format: .{}. Skipping output".format(file_suffix), OutputWarning) warnings.warn("Unknown output format: .{}. Skipping output".format(file_suffix), OutputWarning)
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
...@@ -205,5 +203,3 @@ def _sources(p,path_base): ...@@ -205,5 +203,3 @@ def _sources(p,path_base):
out += "<a href='file://{2}' title='{3}'>{0}</a>:{1}<br />"\ out += "<a href='file://{2}' title='{3}'>{0}</a>:{1}<br />"\
.format(link_text,line_num,full_path,source_file) .format(link_text,line_num,full_path,source_file)
return out return out
from __future__ import unicode_literals
import datetime import datetime
import os import os
import re import re
...@@ -5,7 +7,7 @@ import re ...@@ -5,7 +7,7 @@ import re
from dorie.utilities.check_path import check_path from dorie.utilities.check_path import check_path
from dorie.parscraper.parameter import Parameter from dorie.parscraper.parameter import Parameter
def write(parameters,out,**kwargs): def write(parameters,out,*args,**kwargs):
""" """
Writes the contents of the ``parameters`` input dict to a .ini file. The output is Writes the contents of the ``parameters`` input dict to a .ini file. The output is
structured as structured as
......
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
...@@ -105,5 +103,3 @@ def _sources(p,path_base): ...@@ -105,5 +103,3 @@ def _sources(p,path_base):
out += "`{0} <file://{2}>`_:{1}\n\n"\ out += "`{0} <file://{2}>`_:{1}\n\n"\
.format(link_text,line_num,full_path,source_file) .format(link_text,line_num,full_path,source_file)
return out return out
...@@ -9,7 +9,7 @@ Script invoking the parameter scraper on a folder given via command line. ...@@ -9,7 +9,7 @@ Script invoking the parameter scraper on a folder given via command line.
""" """
if __name__ == "__main__": if __name__ == "__main__":
try: # catch all exceptions we we can output an error message try: # catch all exceptions so we can output an error message
with warnings.catch_warnings(record=True) as warn: # catch all warnings so we can count them with warnings.catch_warnings(record=True) as warn: # catch all warnings so we can count them
# PARSE COMMAND LINE # PARSE COMMAND LINE
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
...@@ -17,25 +17,22 @@ if __name__ == "__main__": ...@@ -17,25 +17,22 @@ if __name__ == "__main__":
parser.add_argument('-s','--source',help='The C++ source folder to scrape',required=True) parser.add_argument('-s','--source',help='The C++ source folder to scrape',required=True)
parser.add_argument('-o','--out',help='Output file(s)',required=True,nargs="*") parser.add_argument('-o','--out',help='Output file(s)',required=True,nargs="*")
parser.add_argument('-c','--css',help='Path to a CSS file to include into HTML output',required=False) parser.add_argument('-c','--css',help='Path to a CSS file to include into HTML output',required=False)
parser.add_argument('-u','--source_url',help='Format string containing path to source files when creating \ parser.add_argument('--debug',help='Display warnings',action='store_true',required=False)
links (optional, default: source_folder/\{filename\}). May contain \{filename\} and \{line\} that are substituted \
by the file name and line number, respectively.',required=False)
parser.add_argument('--Wno',help='Hide warnings (optional, default off)',action='store_true',required=False)
args = vars(parser.parse_args()) args = vars(parser.parse_args())
# CALL WRAPPER # CALL WRAPPER
scrape_folder.scrape(args["xml"],args["source"],args["out"],args["css"],args["source_url"]) scrape_folder.scrape(args["xml"],args["source"],args["out"],args["css"],args["debug"])
# HANDLE WARNINGS # HANDLE WARNINGS
if not "Wno" in args: if not "debug" in args:
debug = False debug = False
else: else:
debug = not args["Wno"] debug = args["debug"]
if debug: if debug:
for w in warn: for w in warn:
print(" {0}: {1}".format(w.category.__name__,w.message)) print(" {0}: {1}".format(w.category.__name__,w.message))
print("-- Parameter scraper exited with ({0}) warning(s) and ({1}) error(s)\n".format(len(warn),0)) print("-- Parameter scraper exited with ({0}) warning(s) and ({1}) error(s)\n".format(len(warn),0))
except Exception as e: except:
print("-- Parameter scraper failed with ({0}) warning(s) and ({1}) error(s):".format(len(warn),1)) print("-- Parameter scraper failed with ({0}) warning(s) and ({1}) error(s):\n".format(len(warn),1))
print("{}: {}\n".format(type(e),e.args[1])) raise
...@@ -170,11 +170,10 @@ class VTKFile: ...@@ -170,11 +170,10 @@ class VTKFile:
""" """
# import these libraries only when needed # import these libraries only when needed
import numpy as np
import matplotlib as mpl import matplotlib as mpl
mpl.use("agg") mpl.use("agg")
import matplotlib.tri as tri
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
if self.grid.dim > 2: if self.grid.dim > 2:
raise TypeError("Only 1- or 2-dimensional grids are supported") raise TypeError("Only 1- or 2-dimensional grids are supported")
...@@ -184,21 +183,9 @@ class VTKFile: ...@@ -184,21 +183,9 @@ class VTKFile:
variables = list(data.keys()) variables = list(data.keys())
x, y = self.grid.cellCenters() x, y = self.grid.cellCenters()
(xt, yt), c = self.grid.triangulation()
try: # check if there already is a triangulation we can use polygons = [[(xt[cii],yt[cii]) for cii in ci] for ci in c]
(xt, yt), c = self.grid.triangulation()
is_rectangular = self.grid.ppc == 4
if is_rectangular:
# create a triangular grid by splitting each rectangle into two
# right-angled triangles
ct = np.array([[x[:-1], x[[0,2,3]]] for x in c]).reshape(-1,3)
triang = tri.Triangulation(xt, yt, ct)
else:
triang = tri.Triangulation(xt, yt, c)
except NotImplementedError:
# create a triangulation by doing a delaunay tessalation of the cell centers
is_rectangular = False
triang = tri.Triangulation(x, y)
figures = [] figures = []
for variable in variables: for variable in variables:
...@@ -213,7 +200,7 @@ class VTKFile: ...@@ -213,7 +200,7 @@ class VTKFile:
else: else:
ncomp = 1 ncomp = 1
fig = plt.figure(figsize=(10,8)) fig, ax = plt.subplots(1,1,figsize=(10,8))
if ncomp > 1: # we are plotting a vector if ncomp > 1: # we are plotting a vector
q = plt.quiver(x, y, d.T[0], d.T[1], angles="xy", scale_units="xy", scale=None, zorder=100) q = plt.quiver(x, y, d.T[0], d.T[1], angles="xy", scale_units="xy", scale=None, zorder=100)
d = np.sqrt(d[:,0]**2 + d[:,1]**2) # use absolute value of d for shading d = np.sqrt(d[:,0]**2 + d[:,1]**2) # use absolute value of d for shading
...@@ -222,23 +209,26 @@ class VTKFile: ...@@ -222,23 +209,26 @@ class VTKFile:
length_significand = round(arrow_length/10**int(np.log10(arrow_length)-1)) length_significand = round(arrow_length/10**int(np.log10(arrow_length)-1))
length_exponent = int(np.log10(arrow_length)-1) length_exponent = int(np.log10(arrow_length)-1)
plt.quiverkey(q, 0.9, 1.05, arrow_length, plt.quiverkey(q, 0.9, 1.05, arrow_length,
'${0} \\cdot 10^{{{1}}} \\frac{{m}}{{s}}$'\ '${0} \\times 10^{{{1}}}$'\
.format(length_significand,length_exponent)) .format(length_significand,length_exponent))
if is_rectangular: plotargs = dict(zorder=1, edgecolors="k", linewidths=0.5)
# data array needs to be repeated because every cell consists of 2 triangles
d = np.repeat(d,2,axis=0)
if np.sign(d.min()) == np.sign(d.max()): if np.sign(d.min()) == np.sign(d.max()):
plotargs = {"cmap": plt.get_cmap("GnBu")} clim = None
plotargs["cmap"] = plt.get_cmap("Blues")
else: else:
maxrange = max(abs(d.min()),abs(d.max())) maxrange = max(abs(d.min()),abs(d.max()))
plotargs = {"cmap": plt.get_cmap("terrain"), "vmin": -maxrange, "vmax": maxrange} clim = (-maxrange,maxrange)
if not is_rectangular: plotargs["cmap"] = plt.get_cmap("RdBu")
plotargs["edgecolors"] = "k" collection = PolyCollection(polygons, **plotargs)
tc = plt.tripcolor(triang,facecolors=d.flatten(),zorder=1,**plotargs) collection.set_array(d.flatten())
if clim:
collection.set_clim(clim)
tc = ax.add_collection(collection)
if not self.time is None: if not self.time is None:
plt.title("{0}: {1} ($t = ${2:.2e}s)".format(self.path,variable,self.time)) plt.title("{0}: {1} ($t = ${2:.2e}s)".format(self.filename,variable,self.time))
else: else:
plt.title("{0}: {1}".format(self.filename,variable)) plt.title("{0}: {1}".format(self.filename,variable))
plt.colorbar(tc, format='%.2e') plt.colorbar(tc, format='%.2e')
figures.append(fig) figures.append(fig)
plt.close()
return figures return figures
...@@ -38,14 +38,14 @@ if __name__ == "__main__": ...@@ -38,14 +38,14 @@ if __name__ == "__main__":
print("Reading VTK file {}".format(f)) print("Reading VTK file {}".format(f))
vtks = [vtkfile.VTKFile(f)] vtks = [vtkfile.VTKFile(f)]
for v in vtks: for vtk in vtks:
print(" Plotting {}...".format(v)) print(" Plotting {}...".format(vtk))
v.read(variables=variables) vtk.read(variables=variables)
if variables is None: if variables is None:
variables = list(v.grid.data().keys()) variables = list(vtk.grid.data().keys())
figures = v.plot(variables=variables) figures = vtk.plot(variables=variables)
for v,fig in zip(variables,figures): for v,fig in zip(variables,figures):
fig.savefig("{}/{}-{}.png".format(out,f,v)) fig.savefig("{}/{}-{}.png".format(out,vtk.filename,v))
# HANDLE WARNINGS # HANDLE WARNINGS
debug = args["Wno"] debug = args["Wno"]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment