Merge branch 'development' of magit1.mpie.de:damask/DAMASK into miscImprovements
This commit is contained in:
commit
4bbd69309d
|
@ -16,9 +16,17 @@ class Test():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
variants = []
|
variants = []
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
|
||||||
def __init__(self,description = ''):
|
defaults = {'description': '',
|
||||||
|
'keep': False,
|
||||||
|
'accept': False,
|
||||||
|
'update': False,
|
||||||
|
}
|
||||||
|
for arg in defaults.keys():
|
||||||
|
setattr(self,arg,kwargs.get(arg) if kwargs.get(arg) else defaults[arg])
|
||||||
|
|
||||||
fh = logging.FileHandler('test.log') # create file handler which logs even debug messages
|
fh = logging.FileHandler('test.log') # create file handler which logs even debug messages
|
||||||
fh.setLevel(logging.DEBUG)
|
fh.setLevel(logging.DEBUG)
|
||||||
fh.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s: \n%(message)s'))
|
fh.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s: \n%(message)s'))
|
||||||
|
@ -34,80 +42,72 @@ class Test():
|
||||||
|
|
||||||
logging.info('\n'.join(['+'*40,
|
logging.info('\n'.join(['+'*40,
|
||||||
'-'*40,
|
'-'*40,
|
||||||
'| '+description,
|
'| '+self.description,
|
||||||
'-'*40,
|
'-'*40,
|
||||||
]))
|
]))
|
||||||
|
|
||||||
self.dirBase = os.path.dirname(os.path.realpath(sys.modules[self.__class__.__module__].__file__))
|
self.dirBase = os.path.dirname(os.path.realpath(sys.modules[self.__class__.__module__].__file__))
|
||||||
|
|
||||||
self.parser = OptionParser(description = '{} (using class: {})'.format(description,damask.version),
|
self.parser = OptionParser(description = '{} (Test class version: {})'.format(self.description,damask.version),
|
||||||
usage = './test.py [options]')
|
usage = './test.py [options]')
|
||||||
self.updateRequested = False
|
self.parser.add_option("-k", "--keep",
|
||||||
self.parser.add_option("-d", "--debug",
|
|
||||||
action = "store_true",
|
action = "store_true",
|
||||||
dest = "debug",
|
dest = "keep",
|
||||||
help = "debug run, don't calculate but use existing results")
|
help = "keep current results, just run postprocessing")
|
||||||
self.parser.add_option("-p", "--pass",
|
self.parser.add_option("--ok", "--accept",
|
||||||
action = "store_true",
|
action = "store_true",
|
||||||
dest = "accept",
|
dest = "accept",
|
||||||
help = "calculate results but always consider test as successfull")
|
help = "calculate results but always consider test as successfull")
|
||||||
self.parser.set_defaults(debug = False,
|
|
||||||
accept = False,
|
self.parser.set_defaults(keep = self.keep,
|
||||||
|
accept = self.accept,
|
||||||
|
update = self.update,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""Run all variants and report first failure."""
|
"""Run all variants and report first failure."""
|
||||||
if self.options.debug:
|
if not self.options.keep:
|
||||||
for variant in xrange(len(self.variants)):
|
|
||||||
try:
|
|
||||||
self.postprocess(variant)
|
|
||||||
if not self.compare(variant):
|
|
||||||
return variant+1 # return culprit
|
|
||||||
except Exception as e :
|
|
||||||
logging.critical('\nWARNING:\n {}\n'.format(e))
|
|
||||||
return variant+1 # return culprit
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
if not self.feasible(): return -1
|
if not self.feasible(): return -1
|
||||||
|
|
||||||
self.clean()
|
self.clean()
|
||||||
self.prepareAll()
|
self.prepareAll()
|
||||||
|
|
||||||
for variant,name in enumerate(self.variants):
|
for variant,name in enumerate(self.variants):
|
||||||
try:
|
try:
|
||||||
|
if not self.options.keep:
|
||||||
self.prepare(variant)
|
self.prepare(variant)
|
||||||
self.run(variant)
|
self.run(variant)
|
||||||
self.postprocess(variant)
|
|
||||||
if self.updateRequested: # update requested
|
|
||||||
self.update(variant)
|
|
||||||
elif not (self.options.accept or self.compare(variant)): # no update, do comparison
|
|
||||||
return variant+1 # return culprit
|
|
||||||
except Exception as e :
|
|
||||||
logging.critical('\nWARNING:\n {}\n'.format(e))
|
|
||||||
return variant+1 # return culprit
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
self.postprocess(variant)
|
||||||
|
|
||||||
|
if self.options.update and not self.update(variant):
|
||||||
|
logging.critical('update for "{}" failed.'.format(name))
|
||||||
|
elif not (self.options.accept or self.compare(variant)): # no update, do comparison
|
||||||
|
return variant+1 # return culprit
|
||||||
|
|
||||||
|
except Exception as e :
|
||||||
|
logging.critical('exception during variant execution: {}'.format(e))
|
||||||
|
return variant+1 # return culprit
|
||||||
|
return 0
|
||||||
|
|
||||||
def feasible(self):
|
def feasible(self):
|
||||||
"""Check whether test is possible or not (e.g. no license available)."""
|
"""Check whether test is possible or not (e.g. no license available)."""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
"""Delete directory tree containing current results."""
|
"""Delete directory tree containing current results."""
|
||||||
status = True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(self.dirCurrent())
|
shutil.rmtree(self.dirCurrent())
|
||||||
except:
|
except:
|
||||||
logging.warning('removal of directory "{}" not possible...'.format(self.dirCurrent()))
|
logging.warning('removal of directory "{}" not possible...'.format(self.dirCurrent()))
|
||||||
status = status and False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.mkdir(self.dirCurrent())
|
os.mkdir(self.dirCurrent())
|
||||||
|
return True
|
||||||
except:
|
except:
|
||||||
logging.critical('creation of directory "{}" failed...'.format(self.dirCurrent()))
|
logging.critical('creation of directory "{}" failed.'.format(self.dirCurrent()))
|
||||||
status = status and False
|
return False
|
||||||
|
|
||||||
return status
|
|
||||||
|
|
||||||
def prepareAll(self):
|
def prepareAll(self):
|
||||||
"""Do all necessary preparations for the whole test"""
|
"""Do all necessary preparations for the whole test"""
|
||||||
return True
|
return True
|
||||||
|
@ -134,8 +134,8 @@ class Test():
|
||||||
|
|
||||||
def update(self,variant):
|
def update(self,variant):
|
||||||
"""Update reference with current results."""
|
"""Update reference with current results."""
|
||||||
logging.debug('Update not necessary')
|
logging.critical('update not supported.')
|
||||||
return True
|
return False
|
||||||
|
|
||||||
|
|
||||||
def dirReference(self):
|
def dirReference(self):
|
||||||
|
@ -458,12 +458,12 @@ class Test():
|
||||||
|
|
||||||
|
|
||||||
def compare_Tables(self,
|
def compare_Tables(self,
|
||||||
files = [None,None], # list of file names
|
files = [None,None], # list of file names
|
||||||
columns = [None], # list of list of column labels (per file)
|
columns = [None], # list of list of column labels (per file)
|
||||||
rtol = 1e-5,
|
rtol = 1e-5,
|
||||||
atol = 1e-8,
|
atol = 1e-8,
|
||||||
debug = False):
|
debug = False):
|
||||||
"""compare tables with np.allclose"""
|
"""compare multiple tables with np.allclose"""
|
||||||
if not (isinstance(files, Iterable) and not isinstance(files, str)): # check whether list of files is requested
|
if not (isinstance(files, Iterable) and not isinstance(files, str)): # check whether list of files is requested
|
||||||
files = [str(files)]
|
files = [str(files)]
|
||||||
|
|
||||||
|
@ -477,7 +477,7 @@ class Test():
|
||||||
columns = columns[:len(files)] # truncate to same length as files
|
columns = columns[:len(files)] # truncate to same length as files
|
||||||
|
|
||||||
for i,column in enumerate(columns):
|
for i,column in enumerate(columns):
|
||||||
if column is None: columns[i] = tables[i].labels(raw = True) # if no column is given, use all
|
if column is None: columns[i] = tables[i].labels(raw = False) # if no column is given, use all
|
||||||
|
|
||||||
logging.info('comparing ASCIItables')
|
logging.info('comparing ASCIItables')
|
||||||
for i in xrange(len(columns)):
|
for i in xrange(len(columns)):
|
||||||
|
@ -485,35 +485,38 @@ class Test():
|
||||||
([columns[i]] if not (isinstance(columns[i], Iterable) and not isinstance(columns[i], str)) else \
|
([columns[i]] if not (isinstance(columns[i], Iterable) and not isinstance(columns[i], str)) else \
|
||||||
columns[i]
|
columns[i]
|
||||||
)
|
)
|
||||||
logging.info(files[i]+':'+','.join(columns[i]))
|
logging.info(files[i]+': '+','.join(columns[i]))
|
||||||
|
|
||||||
# peek into the ASCII table to figure out real table size
|
dimensions = tables[0].label_dimension(columns[0]) # width of each requested column
|
||||||
# the cryptic table header does not share the same size as real
|
maximum = np.zeros_like(columns[0],dtype=float) # one magnitude per column entry
|
||||||
# table
|
data = [] # list of feature table extracted from each file (ASCII table)
|
||||||
table.data_readArray(columns[0])
|
|
||||||
maximum = np.zeros(table.data.shape[1], dtype='f')
|
|
||||||
data = [] # list of feature table extracted from each file (ASCII table)
|
|
||||||
for table, labels in zip(tables, columns):
|
|
||||||
table.data_readArray(labels)
|
|
||||||
for label in labels:
|
|
||||||
idx = table.label_indexrange(label)
|
|
||||||
maximum[idx] = np.maximum(maximum[idx],
|
|
||||||
np.amax(np.linalg.norm(table.data[:,idx],axis=1)))
|
|
||||||
data.append(table.data)
|
|
||||||
table.close()
|
|
||||||
|
|
||||||
maximum = np.where(maximum > 0.0, maximum, 1) # avoid div by zero for empty columns
|
for i,(table,labels) in enumerate(zip(tables,columns)):
|
||||||
|
if np.any(dimensions != table.label_dimension(labels)): # check data object consistency
|
||||||
|
logging.critical('Table {} differs in data layout.'.format(files[i]))
|
||||||
|
return False
|
||||||
|
table.data_readArray(labels) # read data, ...
|
||||||
|
data.append(table.data) # ... store, ...
|
||||||
|
table.close() # ... close
|
||||||
|
|
||||||
|
for j,label in enumerate(labels): # iterate over object labels
|
||||||
|
maximum[j] = np.maximum(\
|
||||||
|
maximum[j],
|
||||||
|
np.amax(np.linalg.norm(table.data[:,table.label_indexrange(label)],
|
||||||
|
axis=1))
|
||||||
|
) # find maximum Euclidean norm across rows
|
||||||
|
|
||||||
|
maximum = np.where(maximum > 0.0, maximum, 1.0) # avoid div by zero for zero columns
|
||||||
|
maximum = np.repeat(maximum,dimensions) # spread maximum over columns of each object
|
||||||
|
|
||||||
# normalize each table
|
|
||||||
for i in xrange(len(data)):
|
for i in xrange(len(data)):
|
||||||
data[i] /= maximum
|
data[i] /= maximum # normalize each table
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
logging.debug(str(maximum))
|
logging.debug(str(maximum))
|
||||||
allclose = np.absolute(data[0]-data[1]) <= (atol + rtol*np.absolute(data[1]))
|
allclose = np.absolute(data[0]-data[1]) <= (atol + rtol*np.absolute(data[1]))
|
||||||
for ok,valA,valB in zip(allclose,data[0],data[1]):
|
for ok,valA,valB in zip(allclose,data[0],data[1]):
|
||||||
logging.debug('{}:\n {}\n{}\n'.format(ok,valA,valB))
|
logging.debug('{}:\n{}\n{}'.format(ok,valA,valB))
|
||||||
|
|
||||||
allclose = True # start optimistic
|
allclose = True # start optimistic
|
||||||
for i in xrange(1,len(data)):
|
for i in xrange(1,len(data)):
|
||||||
|
|
Loading…
Reference in New Issue