-
Notifications
You must be signed in to change notification settings - Fork 16
/
AutoQC.py
129 lines (109 loc) · 3.76 KB
/
AutoQC.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from wodpy import wod
import pickle, sys, os, calendar, time, ast, getopt
import numpy as np
import util.main as main
from multiprocessing import Pool
def run(test, profiles, parameters):
'''
run <test> on a list of <profiles>, return an array summarizing when exceptions were raised
'''
verbose = []
exec('from qctests import ' + test)
for profile in profiles:
exec('verbose.append(' + test + '.test(profile, parameters))')
return verbose
def process_row(uid, logdir, table='iquod', targetdb='iquod.db'):
'''run all tests on the indicated database row'''
# reroute stdout, stderr to separate files for each profile to preserve logs
sys.stdout = open(logdir + "/" + str(uid) + ".stdout", "w")
sys.stderr = open(logdir + "/" + str(uid) + ".stderr", "w")
# extract profile
profile = main.get_profile_from_db(uid, table, targetdb)
# mask out error codes in temperature data
main.catchFlags(profile)
# run tests
for itest, test in enumerate(testNames):
try:
result = run(test, [profile], parameterStore)[0]
except:
print(test, 'exception', sys.exc_info())
result = np.zeros(profile.n_levels(), dtype=bool)
try:
query = "UPDATE " + table + " SET " + test.lower() + "=? WHERE uid=" + str(profile.uid()) + ";"
main.dbinteract(query, [main.pack_array(result)], targetdb=targetdb)
except:
print('db exception', sys.exc_info())
########################################
# main
########################################
# parse options
options, remainder = getopt.getopt(sys.argv[1:], 't:d:b:n:p:l:h')
cores=1
targetdb = 'iquod.db'
dbtable = 'iquod'
logdir = '/AutoQClogs'
batchnumber = None
nperbatch = None
for opt, arg in options:
if opt == '-b':
batchnumber = ast.literal_eval(arg)
if opt == '-d':
dbtable = arg
if opt == '-l':
logdir = arg
if opt == '-n':
cores = ast.literal_eval(arg)
if opt == '-p':
nperbatch = ast.literal_eval(arg)
if opt == '-t':
targetdb = arg
if opt == '-h':
print('usage:')
print('-b <batch number to process>')
print('-d <db table name to create and write to>')
print('-l <directory to write logfiles to>')
print('-n <number of cores to use>')
print('-p <how many profiles to process per batch>')
print('-t <name of db file>')
print('-h print this help message and quit')
# Identify and import tests
testNames = main.importQC('qctests')
testNames.sort()
print('{} quality control checks have been found'.format(len(testNames)))
testNames = main.checkQCTestRequirements(testNames)
print('{} quality control checks are able to be run:'.format(len(testNames)))
for testName in testNames:
print(' {}'.format(testName))
# set up a directory for logging
logdir = logdir + "/autoqc-logs-" + str(calendar.timegm(time.gmtime()))
os.makedirs(logdir)
# Parallel processing.
print('\nPlease wait while QC is performed\n')
# set up global parmaeter store
parameterStore = {
"table": dbtable,
"db": targetdb
}
for test in testNames:
exec('from qctests import ' + test)
try:
exec(test + '.loadParameters(parameterStore)')
except:
print('No parameters to load for', test)
# connect to database & fetch list of all uids
query = 'SELECT uid FROM ' + dbtable + ' ORDER BY uid;'
uids = main.dbinteract(query, targetdb=targetdb)
# launch async processes
if batchnumber is not None and nperbatch is not None:
batchnumber = int(batchnumber)
nperbatch = int(nperbatch)
startindex = batchnumber*nperbatch
endindex = min((batchnumber+1)*nperbatch,len(uids))
else:
startindex = 0
endindex = len(uids)
pool = Pool(processes=int(cores))
for i in range(startindex, endindex):
pool.apply_async(process_row, (uids[i][0], logdir, dbtable, targetdb))
pool.close()
pool.join()