Skip to content
Snippets Groups Projects
Commit 290deb01 authored by Dominic Kempf's avatar Dominic Kempf
Browse files

Rewrite options such that they can be constructed without the commandline parser

parent 75e9e2df
No related branches found
No related tags found
No related merge requests found
......@@ -114,7 +114,7 @@ function(add_generated_executable)
--operator-file ${GEN_OPERATOR}
--driver-file ${GEN_DRIVER}
${GEN_FORM_COMPILER_ARGS}
${GEN_UFLFILE}
--uflfile ${GEN_UFLFILE}
DEPENDS ${GEN_UFLFILE} ${UFL2PDELAB_SOURCES} ${GEN_DEPENDS}
COMMENT "Running ufl2pdelab for the target ${GEN_TARGET}"
)
......
......@@ -14,7 +14,7 @@ from dune.perftool.generation import (delete_cache_items,
global_context,
)
from dune.perftool.interactive import start_interactive_session
from dune.perftool.options import get_option
from dune.perftool.options import get_option, initialize_options
from dune.perftool.pdelab.driver import generate_driver
from dune.perftool.pdelab.localoperator import (generate_localoperator_basefile,
generate_localoperator_file,
......@@ -102,6 +102,7 @@ def read_ufl(uflfile):
# This function is the entrypoint of the ufl2pdelab executable
def compile_form():
initialize_options()
formdatas, data = read_ufl(get_option("uflfile"))
with global_context(data=data, formdatas=formdatas):
......
""" Manage the command line options to the form compiler executable """
from argparse import ArgumentParser
from os import path
from pytools import memoize
from os.path import abspath
from pytools import ImmutableRecord
from dune.common.parametertree.parser import parse_ini_file
@memoize
def get_form_compiler_arguments():
# define an argument parser.
parser = ArgumentParser(description="Compile UFL files to PDELab C++ code", epilog="Please report bugs to dominic.kempf@iwr.uni-heidelberg.de")
parser.add_argument("uflfile", type=str, nargs=1, help="the UFL file to compile")
parser.add_argument("--driver-file", type=str, help="The filename for the generated driver header")
parser.add_argument("--operator-file", type=str, help="The filename for the generated local operator header")
class PerftoolOption(ImmutableRecord):
""" Data structure representing a single formcompiler option """
def __init__(self,
default=None,
helpstr="Undocumented feature!",
process=lambda x: x,
type=type(None),
):
ImmutableRecord.__init__(self,
helpstr=helpstr,
default=default,
process=process,
type=type,
)
class PerftoolOptionsArray(ImmutableRecord):
""" A collection of form compiler arguments """
def __init__(self, **kwargs):
opts = {k: v.default for k, v in PerftoolOptionsArray.__dict__.items() if isinstance(v, PerftoolOption)}
opts.update(kwargs)
ImmutableRecord.__init__(self, **opts)
uflfile = PerftoolOption(helpstr="the UFL file to compile", process=abspath)
driver_file = PerftoolOption(helpstr="The filename for the generated driver header", process=abspath)
operator_file = PerftoolOption(helpstr="The filename for the generated local operator header", process=abspath)
numerical_jacobian = PerftoolOption(default=False, helpstr="use numerical jacobians (only makes sense, if uflpdelab for some reason fails to generate analytic jacobians)")
matrix_free = PerftoolOption(default=False, helpstr="Use iterative solver with matrix free jacobian application")
explicit_time_stepping = PerftoolOption(default=False, helpstr="use explicit time stepping")
exact_solution_expression = PerftoolOption(helpstr="name of the exact solution expression in the ufl file")
compare_dofs = PerftoolOption(helpstr="maximal allowed maximum error of difference between degrees of freedom vectors of numerical solution and interpolation of exact solution (NOTE: requires --exact-solution-expression)")
compare_l2errorsquared = PerftoolOption(helpstr="maximal allowed l2 error squared of difference between numerical solution and interpolation of exact solution (NOTE: requires --exact-solution-expression)")
interactive = PerftoolOption(default=False, helpstr="whether the optimization process should be guided interactively (also useful for debugging)")
print_transformations = PerftoolOption(default=False, helpstr="print out dot files after ufl tree transformations")
print_transformations_dir = PerftoolOption(default=".", helpstr="place where to put dot files (can be omitted)", process=abspath)
quadrature_order = PerftoolOption(type=int, helpstr="Quadrature order used for all integrals.")
diagonal_transformation_matrix = PerftoolOption(default=False, helpstr="set option if the jacobian of the transformation is diagonal (axiparallel grids)")
constant_transformation_matrix = PerftoolOption(default=False, helpstr="set option if the jacobian of the transformation is constant on a cell")
ini_file = PerftoolOption(helpstr="An inifile to use. A generated driver will be hard-coded to it, a [formcompiler] section will be used as default values to form compiler arguments (use snake case)", process=abspath)
opcounter = PerftoolOption(default=False, helpstr="Count operations. Note: In this case only oparor applications are generated since solving and operator counting does not work. You probably want to set instrumentation level>0.")
time_opcounter = PerftoolOption(default=False, helpstr="Generate opcounter codepath. Can be used for timing opcounter programs without setting the opcounter option.")
instrumentation_level = PerftoolOption(default=0, helpstr="Control time/opcounter measurements. 0-do nothing, 1-measure program as a whole, 2-operator applications, 3-measure kernel (eg. alpha-volume, ...), 4-parts of kernel (eg. stage 1-3 of SF)")
project_basedir = PerftoolOption(helpstr="The base (build) directory of the dune-perftool project", process=abspath)
fastdg = PerftoolOption(default=False, helpstr="Use FastDGGridOperator from PDELab.")
sumfact = PerftoolOption(default=False, helpstr="Use sumfactorization")
vectorize_quad = PerftoolOption(default=False, helpstr="whether to generate code with explicit vectorization")
vectorize_grads = PerftoolOption(default=False, helpstr="whether to generate code with explicit vectorization")
turn_off_diagonal_jacobian = PerftoolOption(default=False, helpstr="Do not use diagonal_jacobian transformation on the ufl tree and cast result of jacobianInverseTransposed into a FieldMatrix.")
# Until more sophisticated logic is needed, we keep the actual option data in this module
_options = PerftoolOptionsArray()
def initialize_options():
""" This should be called in entrypoint methods to correctly set up an options array """
global _options
_options = update_options_from_commandline(_options)
_options = update_options_from_inifile(_options)
def update_options_from_commandline(opt):
""" Return an options array object with updated values from the commandline """
assert isinstance(opt, PerftoolOptionsArray)
parser = ArgumentParser(description="Compile UFL files to PDELab C++ code",
epilog="Please report bugs to dominic.kempf@iwr.uni-heidelberg.de",
)
parser.add_argument('--version', action='version', version='%(prog)s 0.1')
parser.add_argument("--numerical-jacobian", action="store_true", help="use numerical jacobians (only makes sense, if uflpdelab for some reason fails to generate analytic jacobians)")
parser.add_argument("--matrix-free", action="store_true", help="use iterative solver with matrix free jacobian application")
parser.add_argument("--explicit-time-stepping", action="store_true", help="use explicit time stepping")
parser.add_argument(
"--exact-solution-expression",
type=str,
help="name of the exact solution expression in the ufl file")
parser.add_argument(
"--compare-dofs",
type=str,
help="maximal allowed maximum error of difference between degrees of freedom vectors of numerical solution and interpolation of exact solution (NOTE: requires --exact-solution-expression)"
)
parser.add_argument(
"--compare-l2errorsquared",
type=str,
help="maximal allowed l2 error squared of difference between numerical solution and interpolation of exact solution (NOTE: requires --exact-solution-expression)"
)
parser.add_argument("--interactive", action="store_true", help="whether the optimization process should be guided interactively (also useful for debugging)")
parser.add_argument("--print-transformations", action="store_true", help="print out dot files after ufl tree transformations")
parser.add_argument("--print-transformations-dir", type=str, help="place where to put dot files (can be omitted)")
parser.add_argument("--quadrature-order", type=int, help="Quadrature order used for all integrals.")
parser.add_argument("--diagonal-transformation-matrix", action="store_true", help="set option if the jacobian of the transformation is diagonal (axiparallel grids)")
parser.add_argument("--constant-transformation-matrix", action="store_true", help="set option if the jacobian of the transformation is constant on a cell")
parser.add_argument("--ini-file", type=str, help="An inifile to use. A generated driver will be hard-coded to it, a [formcompiler] section will be used as default values to form compiler arguments (use snake case)")
parser.add_argument("--opcounter", action="store_true", help="Count operations. Note: In this case only oparor applications are generated since solving and operator counting does not work. You probably want to set instrumentation level>0.")
parser.add_argument("--time-opcounter", action="store_true", help="Generate opcounter codepath. Can be used for timing opcounter programs without setting the opcounter option.")
parser.add_argument("--instrumentation-level", type=int, default=0, help="Control time/opcounter measurements. 0-do nothing, 1-measure program as a whole, 2-operator applications, 3-measure kernel (eg. alpha-volume, ...), 4-parts of kernel (eg. stage 1-3 of SF)")
parser.add_argument("--project-basedir", type=str, help="The base (build) directory of the dune-perftool project")
parser.add_argument("--fastdg", action="store_true", help="Use FastDGGridOperator from PDELab.")
# TODO at some point this help description should be updated
parser.add_argument("--sumfact", action="store_true", help="Use sumfactorization")
parser.add_argument("--vectorize-quad", action="store_true", help="whether to generate code with explicit vectorization")
parser.add_argument("--vectorize-grads", action="store_true", help="whether to generate code with explicit vectorization")
parser.add_argument("--turn-off-diagonal-jacobian", action="store_true", help="Do not use diagonal_jacobian transformation on the ufl tree and cast result of jacobianInverseTransposed into a FieldMatrix.")
# Modify the positional argument to not be a list
args = vars(parser.parse_args())
# Delistify the uflfile parameter
args["uflfile"] = args["uflfile"][0]
# Turn any relative paths into absolute ones for consistency
if args["driver_file"]:
args["driver_file"] = path.abspath(args["driver_file"])
if args["operator_file"]:
args["operator_file"] = path.abspath(args["operator_file"])
if args["ini_file"]:
args["ini_file"] = path.abspath(args["ini_file"])
# Return the argument dict. This result is memoized to turn all get_option calls into simple dict lookups.
return args
_option_dict = {}
_arguments_read = False
def init_option_dict():
"""Add form compile arguments to options dict"""
global _arguments_read
if not _arguments_read:
_option_dict.update(get_form_compiler_arguments())
_arguments_read = True
# Read arguments from the given inifile
if _option_dict["ini_file"]:
inifile = parse_ini_file(_option_dict["ini_file"])
for key, value in inifile.get("formcompiler", {}).items():
if key not in _option_dict or _option_dict[key] is None:
_option_dict[key] = value
elif not _option_dict[key]:
# As `bool("0")` is True, we need to eval bools
if isinstance(_option_dict[key], bool):
_option_dict[key] = eval(value)
else:
_option_dict[key] = type(_option_dict[key])(value)
for k, v in type(opt).__dict__.items():
if isinstance(v, PerftoolOption):
cmdopt = "--{}".format(k.replace('_', '-'))
_type = v.type
if _type is type(None):
_type = type(v.default)
if _type is type(None):
_type = str
parser.add_argument(cmdopt, help=v.helpstr, type=_type)
parsedargs = {k: v for k, v in vars(parser.parse_args()).items() if v is not None}
return opt.copy(**parsedargs)
def update_options_from_inifile(opt):
""" Return an options array object with updated values from an inifile """
if opt.ini_file:
opt = opt.copy(**parse_ini_file(opt.ini_file).get("formcompiler", {}))
return opt
def set_option(key, value):
......@@ -101,22 +103,12 @@ def set_option(key, value):
any other options.
"""
# Make sure form compile arguments were read
init_option_dict()
global _options
_options = _options.copy(key=value)
_option_dict.update({key: value})
def get_option(key, default=None):
try:
__IPYTHON__
return default
except:
"""Return the value corresponding to key from option dictionary"""
# Make sure form compile arguments were read
init_option_dict()
return _option_dict.get(key, default)
def get_option(key):
return getattr(_options, key)
def option_switch(opt):
......
......@@ -20,9 +20,9 @@ class UFLTransformationWrapper(object):
# Write out a dot file
from dune.perftool.options import get_option
if get_option("print_transformations", False):
if get_option("print_transformations"):
import os
dir = get_option("print_transformations_dir", os.getcwd())
dir = get_option("print_transformations_dir")
for i, exprtowrite in enumerate(expr):
filename = "trafo_{}_{}_{}{}.dot".format(self.name, str(self.counter).zfill(4), "in" if before else "out", "_{}".format(i) if len(expr) > 1 else "")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment