12 from optparse
import OptionParser
21 import scipy.interpolate
22 from scipy.integrate
import quadrature
28 import matplotlib.pyplot
as plt
29 from matplotlib.backends.backend_pdf
import PdfPages
30 from matplotlib.font_manager
import FontProperties
36 logging.basicConfig(level=logging.DEBUG, format=
"%(asctime)s %(levelname)s %(message)s")
49 if exc.errno == errno.EEXIST:
61 if e.errno != errno.ENOENT:
68 if format
is None:
return np.genfromtxt(fname)
70 floatingReString=
r'([-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?)'
71 complexReString =
r'\(\s*'+floatingReString+
'\s*,\s*'+floatingReString+
'\s*\)'
73 return np.fromregex(fname,format.replace(
r'+',
r'\s*').replace(
'f',floatingReString).replace(
'c',complexReString),np.float)
77 def PTLA_postprocess(input):
78 result=np.zeros((input.shape[0],6))
79 result[:,[0,1]]=input[:,[0,1]]
80 result[:,2]=(1+input[:,2])/2
81 result[:,3]=(1-input[:,2])/2
82 result[:,4]=input[:,3]/2
83 result[:,5]=input[:,4]/2
86 def PLM_Evolved_postprocess(input):
87 result=np.zeros((input.shape[0],5))
88 result[:,[0,1]]=input[:,[0,1]]
89 result[:,2]=input[:,2]**2+input[:,3]**2
90 result[:,3]=input[:,2]
91 result[:,4]=input[:,3]
102 @ingroup TestclassHelpers
103 \brief Stores command line options and configuration file keys.
105 Each OptionsManager instance has its own section in the configuration file, named after
106 the current test name (OptionsManager::test). If the current section has the key
107 `import=othersection`, import all keys from `othersection` if they are not present already
108 (works recursively). Values which end in `_local` are never imported.
110 \ref OptionsManager_options "Command line" options this class understands.
122 @param options optparse.Values: object holding all the command line options.
123 @param cp ConfigParser: ConfigParser instance holding all configuration file keys.
132 if not self.
test: sys.exit(
'--test missing')
134 def _import_section(self,section=None):
135 if section
is None: section = self.
test
136 if self.cp.has_option(section,
'import'):
137 import_section=self.cp.get(section,
'import')
139 for item
in self.cp.items(import_section):
140 if not self.cp.has_option(section,item[0])
and not item[0].endswith(
'_local'):
141 self.cp.set(section, *item)
142 self.cp.remove_option(section,
'import')
144 def get_option(self, name, default=None, required=False, section=None):
146 Get configuration file keys in a safe way.
147 \param name Name of the key.
148 \param default Default value to return if key does not exist.
149 \param required Fail if True and key does not exist.
150 \param section The section name to look in, defaults to OptionsManager::test if None.
151 \return The value to the key.
153 This methods looks up the key `name` in the section name OptionsManager::test.
155 if section
is None: section=self.
test
157 if self.cp.has_option(section,name):
158 return self.cp.get(section,name)
160 if not required:
return default
161 else: sys.exit(
"Error: required option \"{0}\" not found in section {1}.".format(name,section))
165 @ingroup TestclassHelpers
166 \brief Manages output files for different run modes.
168 \ref OutputManager_keys "Configuration file keys" this class understands.
186 Arguments are passed through to OptionsManager.
188 OptionsManager.__init__(self, *args, **kwargs)
198 \param section (optional) String: Where to look up the runmodes, take current test section if not specified.
199 \return A list of runmodes in this section.
201 if section
is None: section=self.
test
202 return self.
get_option(
'runmodes', section=section, default=
'generic').split(
',')
204 def _filter_runmodes(self, section):
205 filter_runmodes=self.
get_option(
'runmodes_'+self.
test+
'_local',section=section)
206 if not filter_runmodes
is None: filter_runmodes=filter_runmodes.split(
',')
207 for mode
in self.
runmodes(section=section):
208 if not filter_runmodes
is None and not mode
in filter_runmodes:
continue
211 def output(self, runmode, section=None, statefile=False):
213 The name of the output file for a given runmode.
214 \param runmode String: The runmode for which the filename should be generated.
215 \param section (optional) String: Output file name for which section, current test section if left empty.
216 \param statefile (optional) Boolean: By default generate the file name for a trajectory file. If set to true
217 generate the file name for a state file.
218 \return Full path including OutputManager::outputdir.
220 if section
is None: section=self.
test
221 if runmode ==
"generic":
222 output = os.path.join(self.
outputdir, section)
224 output = os.path.join(self.
outputdir, section+
'_'+runmode)
225 if statefile: output+=
".state"
230 Delete the trajectory file and state file for a given runmode.
231 \param runmode String: The runmode for which output files should be deleted.
242 Runs a script repeatedly for all declared runmodes and succeeds if the scripts do.
244 \ref Runner_keys "Configuration file keys" this class understands.
246 def run(self, clean=True, extra_opts=None, interpreter=None, *args, **kwargs):
248 The method to run the test.
249 \param clean (optional) `Boolean`: Whether to remove old output before running the test.
250 \param extra_opts (optional) `List`: Additional command line options appended to the script call.
251 \param interpreter (optional) `str`: Interpreter to run the command through, e.g. `python`.
252 \param args passed through to `subprocess.call`
253 \param kwargs passed through to `subprocess.call`
255 This method terminates the test driver with a return value equal to that of the script call
256 if one of the scripts fail.
259 if clean: self.
clean(runmode)
261 logging.debug(subprocess.list2cmdline(command))
262 ret = subprocess.call(command, *args, **kwargs)
263 if not ret==0: sys.exit(ret)
285 def _extend_opts(self, options, section, option_prefix):
286 for option
in sorted([ item[0]
for item
in self.cp.items(section)
if item[0].startswith(option_prefix)]):
287 options.extend(self.cp.get(section,option).split())
289 def _build_commandline(self, runmode, extra_opts=None, interpreter=None):
290 result = [interpreter]
if not interpreter
is None else []
291 result.append(self.options.script)
292 if extra_opts: result+=extra_opts
302 if not runmode==
"generic": result.extend((
'--evol',runmode))
303 result.extend((
'--o',self.
output(runmode)))
309 Runs a cpypyqed script repeatedly for all declared runmodes and succeeds if the scripts do.
311 \ref PythonRunner_options "Configuration file keys" this class understands.
321 def run(self, clean=True, extra_opts=None, *args, **kwargs):
323 The method to run the test.
324 \param clean (optional) `Boolean`: Whether to remove old output before running the test.
325 \param extra_opts (optional) `List`: Additional command line options appended to the script call.
326 \param args passed through to Runner.run()
327 \param kwargs passed through to Runner.run()
329 This method terminates the test driver with a return value equal to that of the script call
330 if one of the scripts fail.
332 cpypyqed_builddir = self.options.cpypyqed_builddir
333 cpypyqed_config = self.options.cpypyqed_config
334 env = os.environ.copy()
335 if cpypyqed_builddir:
336 env[
'CPYPYQED_BUILDDIR']=cpypyqed_builddir
337 if clean: shutil.rmtree(os.path.join(cpypyqed_builddir,
'cppqedmodules'),ignore_errors=
True)
338 if cpypyqed_config: env[
'CPYPYQED_CONFIG']=cpypyqed_config
339 env[
'PYTHONPATH']=self.cp.get(
'Setup',
'modulepath')
340 if extra_opts
is None: extra_opts = []
341 if self.options.configuration.lower()==
"debug": extra_opts += [
'--debug']
342 Runner.run(self,clean=clean,extra_opts=extra_opts,interpreter=sys.executable,env=env,*args,**kwargs)
347 Verifies the output of a script 'this' to an expected output or the output of some other test run 'other'
349 \ref Verifier_keys "Configuration file keys" this class understands.
371 \param args passed through to OutputManager
372 \param kwargs passed through to OutputManager
374 OutputManager.__init__(self,*args,**kwargs)
383 if mode
is None or mode==
'full':
385 elif mode==
'outcome':
387 def _verify_full(self):
391 def _thisOutput(self,runmode,statefile=False):
393 def _otherOutput(self,runmode,statefile=False):
398 def _differ(self,this,other):
399 sys.exit(
"Error: {0} and {1} differ.".format(this,other))
400 def _equiv(self,this,other):
401 logging.debug(
"{0} and {1} are equivalent.".format(this,other))
402 def _verify_ev(self,this,other):
404 else: self.
_equiv(this,other)
405 def _verify_state(self,this,other):
406 _,r_state,r_time = io.read(this)
407 _,e_state,e_time = io.read(other)
408 if not (np.allclose(r_state,e_state)
and np.allclose(r_time,e_time)): self.
_differ(this,other)
409 else: self.
_equiv(this,other)
410 def _verify_outcome(self,this,other):
411 _,r_state,r_time=io.read(this)
412 _,e_state,e_time=io.read(other)
413 if not (np.allclose(r_state[-1],e_state[-1])
and np.allclose(r_time[-1],e_time[-1])):
415 else: self.
_equiv(this,other)
420 Combines the functionality of Runner and Verifier to a single test.
432 @ingroup TestclassHelpers
433 This class hosts continued_run(), which will run and then continue a script.
445 Run, then continue a script.
446 \param runfn Function: The run function to call.
447 \param args passed through to `runfn`
448 \param kwargs passed through to `runfn`
450 runfn(self, extra_opts=self.
get_option(
'firstrun',default=
'').split(), *args, **kwargs)
451 runfn(self, clean=
False, extra_opts=self.
get_option(
'secondrun',default=
'').split(), *args, **kwargs)
456 GenericContinuer version of Runner.
458 \ref GEnericContinuer_keys "Configuration file keys" this class understands.
467 def run(self, *args, **kwargs):
469 Delegates to GenericContinuer::continued_run().
471 GenericContinuer.continued_run(self, Runner.run, *args, **kwargs)
476 GenericContinuer version of PythonRunner.
478 \ref GEnericContinuer_keys "Configuration file keys" this class understands.
487 def run(self, *args, **kwargs):
489 Delegates to GenericContiuer::continued_run().
491 GenericContinuer.continued_run(self, PythonRunner.run, *args, **kwargs)
496 \brief This test tries to compile a %CMake target.
498 If the `--error` option is not given,
499 the test succeeds if the target can be compiled, otherwise the test succeeds if the
500 compilation fails and the string specified together with `--error` is found.
502 \ref CompileTarget_options "Command line options" this class understands.
530 cmake=self.cp.get(
'Setup',
'cmake')
531 builddir=self.cp.get(
'Setup',
'builddir')
532 command=[cmake,
'--build',builddir,
'--target']
533 dependencies=self.
get_option(
'dependencies',default=
"").split()
534 for dep
in dependencies:
535 logging.debug(subprocess.list2cmdline(command+[dep]))
536 p = subprocess.Popen(command+[dep], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
537 (std,err) = p.communicate()
538 if not p.returncode==0:
539 sys.exit(
"Compilation of dependency {0} for {1} failed.".format(dep,self.options.script))
540 logging.debug(subprocess.list2cmdline(command+[self.options.script]))
541 p = subprocess.Popen(command+[self.options.script], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
542 (std,err) = p.communicate()
543 returncode = p.returncode
546 sys.exit(
"Compilation of {0} failed.".format(self.options.script))
549 sys.exit(
"Compilation was successful, but failure was expected.")
550 if (
not error
in std)
and (
not error
in err):
553 sys.exit(
"Compilation failed as expected, but \"{0}\" was not found in the error message.".format(error))
557 \brief This is a helper class which helps with plotting functions to a pdf file.
559 If the global variable `plot` is False, all functions are a no-op.
563 return plot
and not self.
get_option(
'pdf')
is None
566 \brief Initialize a new pdf file.
568 The file is read from the configuration key `pdf`.
570 if not self.
_plot():
return
574 \brief Saves the pdf file to disc after all plots are finished.
576 if not self.
_plot():
return
577 for n
in plt.get_fignums():
584 \brief Adds the current plot to the pdf file.
586 if not self.
_plot():
return
591 \brief Creates a new plot with figure legend right of the plot.
592 \param ylabel The label of the y axis.
593 \param title The title of the plot
594 \param n The value number.
596 if not self.
_plot():
return
597 if n
in plt.get_fignums():
600 f = plt.figure(num=n,figsize=(11.6,8.2))
601 f.add_axes([0.09, 0.1, 0.6, 0.75])
605 def _place_legend(self):
606 if not self.
_plot():
return
607 fontP = FontProperties()
608 fontP.set_size(
'small')
609 leg=plt.legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.,prop = fontP)
610 llines=leg.get_lines()
611 plt.setp(llines, linewidth=1.5)
612 def plot(self,time,data,**kwargs):
614 \brief Wraps matplotlibs plot function.
615 \param time An array of time values.
616 \param data An array of data values.
617 \param **kwargs These are passed to `matplotlib.plot`.
619 if not self.
_plot():
return
620 plt.plot(time,data,**kwargs)
623 def final_temperature(nTh):
626 n=np.arange(state.shape[0],dtype=float)
627 expected_rho=np.diag(nTh**n/(1.+4)**(n+1))
628 return np.sqrt(np.sum(np.abs(state-expected_rho)**2))
634 Tests final states of several trajectories by applying a given function.
636 \ref StateComparer_keys "Configuration file keys" this class understands.
653 trajectories=self.
get_option(
'trajectories',required=
True).split(
',')
654 function=globals()[self.
get_option(
'function',required=
True)]
655 parameters=ast.literal_eval(self.
get_option(
'parameters'))
656 if parameters
is None: parameters=[]
658 for traj
in trajectories:
660 statefile=self.
output(runmode=runmode,section=traj,statefile=
True)
661 _,states,_=io.read(statefile)
662 logging.debug(
"Evaluating {0}.".format(os.path.basename(statefile)))
663 eps=float(self.
get_option(
'epsilon_'+runmode+
'_'+self.
test,section=traj,required=
True))
664 value=function(*parameters)(states)
665 logging.debug(
"Value: {0}, epsilon: {1}".format(value,eps))
668 logging.debug(
"====== FAILED ======")
669 if failure: sys.exit(-1)
675 Compares several trajectories to a reference trajectory by using function interpolation.
677 \ref TrajectoryComparer_keys "Configuration file keys" this class understands.
703 trajectories=self.
get_option(
'trajectories',required=
True).split(
',')
706 reference_plotted=dict()
707 for traj
in trajectories:
712 data,timeArray,data_label=self.
_get_data(section=traj,runmode=runmode,n=n)
713 reference,reference_label=self.
_get_reference(section=traj,runmode=runmode,n=n)
714 if not reference_plotted.has_key((reference_label,n)):
715 self.
plot(timeArray,reference(timeArray),label=reference_label)
716 reference_plotted[(reference_label,n)]=
True
717 self.
plot(timeArray,data(timeArray),label=data_label)
718 logging.debug(
"Evaluating {0}, value number {1}.".format(data_label,n+1))
720 if not self.
_regression(reference,data,timeArray,eps):
721 logging.debug(
"====== FAILED ======")
727 def _get_eps(self, runmode, section, n):
728 return float(self.
get_option(
'epsilon_'+runmode+
'_'+self.
test,section=section,required=
True).split(
',')[n])
730 def _get_columns(self,section,runmode):
731 return map(int,self.
get_option(
'columns_'+self.
test,section=section,required=
True).split(
','))
733 def _get_reference(self,section,runmode,n):
734 reference=self.
get_option(
'reference',required=
True)
735 reference_runmode=self.
runmodes(section=reference)[0]
736 result=self.
_get_data(section=reference,runmode=reference_runmode,n=n)
737 return result[0],result[2]
739 def _get_data(self,section,runmode,n):
740 fname=self.
get_option(
'postprocess_local',section=section)
741 format=self.
get_option(
'format_local',section=section)
744 postprocess=globals()[fname]
if not fname
is None else lambda x: x
745 result=postprocess(
load_sv(self.
output(runmode=runmode,section=section),format=format))
746 if not start
is None: result=result[int(start):]
747 if not length
is None: result=result[:int(length)]
748 timeArray = result[:,0]
750 return self.
_interpolate(timeArray,data),timeArray,os.path.basename(self.
output(runmode,section))
752 def _interpolate(self,timeArray,array):
753 return scipy.interpolate.interp1d(timeArray,array)
755 def _regression(self, f1, f2, timeArray, eps) :
758 res=quadrature(
lambda t : (f1(t)-f2(t))**2,t0,t1,maxiter=100)[0]
759 logging.debug(
"Quadrature: {0}, epsilon: {1}".format(res,eps))
762 def exponential(a,l):
765 return fn,
"{0}*exp(-{1}*t)".format(a,l)
767 def FreeParticleX(x0,p0):
770 return fn,
"{0}+2*{1}*t".format(x0,p0)
772 def FreeParticleVarX(dx0,dp0):
774 return (dx0+4.*dp0*t**2)**.5
775 return fn,
"({0}+(4*{1}*t)^2)^0.5"
780 Compares several trajectories to a reference function by using function interpolation.
782 \ref FunctionComparer_keys "Configuration file keys" this class understands.
795 def _get_reference(self, section, runmode, n):
796 reference = globals()[self.
get_option(
'reference_function', required=
True)]
797 parameters=self.
get_option(
'parameters_'+self.
test, section=section)
798 parameters=()
if parameters
is None else ast.literal_eval(parameters)
799 if type(parameters)==list:parameters=parameters[n]
800 return reference(*parameters)
804 \brief Main function of the Python test driver.
806 Command line options are defined here. It is responsible of loading the right `cpypyqed` module
807 (release or debug) as well as instantiating and running the test class.
810 cp = ConfigParser.SafeConfigParser()
812 op.add_option(
"--test", help=
"the name of the test, and the name of the section in the config file")
813 op.add_option(
"--testclass", help=
"the name of the testclass to use, must implement run()")
814 op.add_option(
"--script", help=
"the script to run or the target to compile")
815 op.add_option(
"--configuration", help=
"debug or release")
816 op.add_option(
"--cpypyqed_builddir", help=
"directory for on-demand module compilation")
817 op.add_option(
"--cpypyqed_config", help=
"configure file for on-demand module compilation")
819 (options,args) = op.parse_args()
821 if len(args)==0: op.error(
"Need configuration file(s) as argument(s).")
823 sys.path.insert(0,cp.get(
'Setup',
'modulepath'))
826 if options.configuration.lower()==
"release":
827 import cpypyqed.io
as io
828 elif options.configuration.lower()==
"debug":
829 import cpypyqed.io_d
as io
830 logging.info(
"Taking cpypyqed from {0}".format(io.__file__))
832 if options.testclass:
833 constructor = globals()[options.testclass]
834 myTestclass = constructor(options,cp)
837 if __name__ ==
'__main__':
def rm_f
Remove a file without error if it doesn't exist.
Runs a cpypyqed script repeatedly for all declared runmodes and succeeds if the scripts do...
def run
Delegates to GenericContinuer::continued_run().
Compares several trajectories to a reference function by using function interpolation.
cp
ConfigParser: configuration file keys.
This is a helper class which helps with plotting functions to a pdf file.
Tests final states of several trajectories by applying a given function.
GenericContinuer version of Runner.
Combines the functionality of Runner and Verifier to a single test.
Stores command line options and configuration file keys.
def close_pdf
Saves the pdf file to disc after all plots are finished.
Compares several trajectories to a reference trajectory by using function interpolation.
def output
The name of the output file for a given runmode.
outputdir
All output files end up here.
Runs a script repeatedly for all declared runmodes and succeeds if the scripts do.
test
The name of the current test.
def load_sv
Loads a trajectory file.
expecteddir
Where to look for pre-run simulations to compare test runs to.
def start_pdf
Initialize a new pdf file.
def get_option
Get configuration file keys in a safe way.
Verifies the output of a script 'this' to an expected output or the output of some other test run 'ot...
def __init__
Arguments are passed through to OptionsManager.
GenericContinuer version of PythonRunner.
def run
The method to run the test.
This test tries to compile a CMake target.
def mkdir_p
Create a directory with parent directories.
def clean
Delete the trajectory file and state file for a given runmode.
def run
Delegates to GenericContiuer::continued_run().
def runmodes
Return runmodes.
options
optparse.Values: command line options
def run
The method to run the test.
def figureLegendRight
Creates a new plot with figure legend right of the plot.
def continued_run
Run, then continue a script.
def finish_plot
Adds the current plot to the pdf file.
Manages output files for different run modes.
This class hosts continued_run(), which will run and then continue a script.
def plot
Wraps matplotlibs plot function.
def main
Main function of the Python test driver.