-
Notifications
You must be signed in to change notification settings - Fork 11
/
KUL_main_functions.sh
executable file
·417 lines (341 loc) · 14.5 KB
/
KUL_main_functions.sh
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
#!/bin/bash
# Bash shell script to:
# - define global functions used by all /DATA/fmri_pats/BIDS/derivatives/KUL_compute/sub-Casier/FastSurfer/sub-Casier/scripts/lh.processing.cmdfsub-scripts
# - define defaults
# - execute startup
#
# @ [email protected] - v0.2 - 18/11/2021
# MAIN FUNCTION - Function task_exec ###################################################################################
# - obligatory variable to set
# task_in (a command string that needs to be evaluated)
# - facultative command line options
# kul_verbose_level (0=silent, 1=normal; 2=verbose; 1=default)
# kul_short_name (what to display as process)
# kul_log_file (the path of the log file)
#
# it will return $total_errorcount in the calling script (a sum of all errors that happened)
#
# Example 1
# task_in="a_big_long_process"
# and also given are: 0
# and also given is: "KUL VBG"
# and also given is: "KUL_LOG/my_big_long_process"
# It will run "process a_big_long_process"
# Do it silently (the 0)
# Display "KUL VBG" as the running process
# Log to the files KUL_LOG/my_big_long_process.log and KUL_LOG/my_big_long_process.error.log
#
# Example 2
# task_in="another big process"
# Run process "another big process"
# It will give output to the terminal and to log files (because default is kul_verbose_level 1)
# Take the first 20 characters of "task_in" and display that (kul_short_name is generated automatically)
# Log to the files another_big_process.log and another_big_process.error.log (/ -> _, and spaces too)
function KUL_task_exec {
# task_in needs to be defined
if [[ -z "$task_in" ]]; then
echo "task_in is not defined, exitting"
exit 1
fi
# task_participant, if undefined, and only 1 task_in, set to current participant, otherwise exit
if [[ -z "$task_participant" ]]; then
if [ ${#task_in[@]} -eq 1 ]; then
task_participant[0]=$participant
else
echo "task_participant is not defined, exitting"
exit 1
fi
fi
#local pidsArray=${task_in_pid[@]} # pids to wait for, separated by semi-colon
#local procsArray=${task_in_name[@]} # name of procs to wait for, separated by semi-colon
local pidsArray=() # pids to wait for, separated by semi-colon
local procsArray=() # name of procs to wait for, separated by semi-colon
local log_ttime=0 # local time instance for comparison
local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function
local pidCount # number of given pids
local c # counter for pids/procsArray
local errorcount=0 # Number of pids that finished with errors
local local_task_in
local local_n_tasks
local local_task_in_name
local local_main_logdir=${cwd}/KUL_LOG/${script}
# get the input variables; a check below wil put default values if $1/$2/$3 are empty
local kul_verbose_level="$1"
local kul_process_name="$2"
local kul_log_files="$3"
if [ $KUL_DEBUG -eq 1 ]; then
echo "kul_verbose_level: $kul_verbose_level"
echo "kul_process_name: $kul_process_name"
echo "kul_log_files: $kul_log_files"
echo "script: $script"
echo "task_in: ${task_in[@]}"
echo "task_participant: ${task_participant[@]}"
fi
# test the input to the function and of unset, set a default
if [[ -z "$kul_verbose_level" ]]; then
kul_verbose_level=1
fi
local_n_tasks=0
for local_task_in in "${task_in[@]}"; do
if [ $KUL_DEBUG -eq 1 ]; then
echo "local_task_in: $local_task_in"
echo "local_n_tasks: $local_n_tasks"
fi
#remove the double (or more) spaces from task_in
local_task_in=$(echo $local_task_in | tr -s ' ')
if [[ -z "$kul_process_name" ]]; then
task_in_name[$local_n_tasks]="$(echo ${local_task_in:0:20} [sub-${task_participant[local_n_tasks]}])"
else
task_in_name[$local_n_tasks]="$kul_process_name [sub-${task_participant[local_n_tasks]}]"
fi
local local_main_logdir_participant="$local_main_logdir/sub-${task_participant[local_n_tasks]}"
if [ ! -d "$local_main_logdir_participant" ]; then
mkdir "$local_main_logdir_participant"
fi
if [[ -z "$kul_log_files" ]]; then
task_in_name_nospaces_tmp="${task_in_name[$local_n_tasks]// /_}"
task_in_name_nospaces="${task_in_name_nospaces_tmp////_}"
kul_log_file[$local_n_tasks]="$local_main_logdir_participant/"${task_in_name_nospaces}".log"
kul_errorlog_file[$local_n_tasks]="$local_main_logdir_participant/"${task_in_name_nospaces}".error.log"
kul_log_command[$local_n_tasks]="$local_main_logdir_participant/"${task_in_name_nospaces}".command"
else
kul_log_file[$local_n_tasks]="$local_main_logdir_participant/"${kul_log_files}.log""
kul_errorlog_file[$local_n_tasks]="$local_main_logdir_participant/"${kul_log_files}.error.log""
kul_log_command[$local_n_tasks]="$local_main_logdir_participant/"${kul_log_files}.command""
fi
### STEP 2 - execute the task_in
if [ $kul_verbose_level -lt 2 ]; then
#echo "using >"
tput dim
local task_in_final="($local_task_in) >>${kul_log_file[$local_n_tasks]} 2>>${kul_errorlog_file[$local_n_tasks]}"
#echo $task_in_final
eval ${task_in_final} &
tput sgr0
else
#echo "using tee"
tput dim
local task_in_final="($local_task_in) > >(tee -a ${kul_log_file[$local_n_tasks]}) 2> >(tee -a ${kul_errorlog_file[$local_n_tasks]})"
eval ${task_in_final} &
tput sgr0
fi
# set the pids, first we get the pid by "$!", then feed it into an array
task_in_pid="$!"
pidsArray+=($task_in_pid)
procsArray+=("${task_in_name[$local_n_tasks]}")
#echo "procsArray: ${procsArray[$local_n_tasks]}"
### STEP 3 - give some information
if [ $kul_verbose_level -gt 0 ]; then
tput bold
echo "KUL_task_exec: ${task_in_name[$local_n_tasks]}... started @ $(date "+%Y-%m-%d_%H-%M-%S")" | tee -a ${kul_log_file[$local_n_tasks]}
tput sgr0
fi
if [ $kul_verbose_level -eq 2 ]; then
tput dim
echo -e " The task_in command: ${local_task_in}" | tee -a ${kul_log_file[$local_n_tasks]}
tput sgr0
fi
# log the command itself
echo ${local_task_in} > ${kul_log_command[$local_n_tasks]}
((local_n_tasks++))
done
### STEP 4 - keep checking if the process is still running
pidCount=${#pidsArray[@]}
#echo " pidCount: $pidCount"
#echo " pidsArray: ${pidsArray[@]}"
#echo " procsArray: ${procsArray[@]}"
while [ ${#pidsArray[@]} -gt 0 ]; do
newPidsArray=()
newProcsArray=()
c=0
total_exec_time=$(($SECONDS - $script_start_time))
#echo $total_exec_time
total_exec_time_min=$(echo "scale=2; $total_exec_time/60" | bc)
## Log a standby message every hour
every_time=1201
exec_time=$(($SECONDS - $seconds_begin))
if [ $((($exec_time + 1) % $every_time)) -eq 0 ]; then
if [ $log_ttime -ne $exec_time ]; then
log_ttime=$exec_time
log_min=$(echo "scale=1; $log_ttime/60" | bc)
if [ $kul_verbose_level -gt 0 ]; then
tput dim
echo " Current tasks [${procsArray[@]}] still running after $log_min minutes with pids [${pidsArray[@]}]."
echo " Total script time: $total_exec_time_min minutes"
tput sgr0
fi
fi
fi
for pid in "${pidsArray[@]}"; do
#echo "pid: $pid"
#echo "proc: ${procsArray[c]}"
if kill -0 $pid > /dev/null 2>&1; then
newPidsArray+=($pid)
#echo "newPidsArray: ${newPidsArray[@]}"
newProcsArray+=("${procsArray[c]}")
#echo "newProcsArray: ${newProcsArray[@]}"
else
wait $pid
result=$?
#echo "result: $result"
if [ $result -ne 0 ]; then
errorcount=$((errorcount+1))
fail_exec_time_seconds=$(($SECONDS - $seconds_begin))
fail_exec_time_minutes=$(echo "scale=1; $final_exec_time_seconds/60" | bc)
tput bold; tput setaf 1
echo " *** WARNING! **** Process ${procsArray[c]} with pid $pid might have failed after $fail_exec_time_minutes minutes. (with exitcode [$result]). Check the ${kul_errorlog_file[$c]} log-file" | tee -a ${kul_errorlog_file[$c]}
tput sgr0
else
final_exec_time_seconds=$(($SECONDS - $seconds_begin))
final_exec_time_minutes=$(echo "scale=2; $final_exec_time_seconds/60" | bc)
if [ $kul_verbose_level -gt 0 ]; then
tput setaf 2
#echo "c: $c"
#echo "procsArray: ${procsArray[c]}"
echo " ${procsArray[c]} finished successfully after $final_exec_time_minutes minutes" | tee -a ${kul_log_file[$c]}
echo " Total script time: $total_exec_time_min minutes"
tput sgr0
fi
fi
fi
c=$((c+1))
done
pidsArray=("${newPidsArray[@]}")
procsArray=("${newProcsArray[@]}")
sleep 1
done
### STEP 5 - return the status of execution
if [ $errorcount -eq 0 ]; then
if [ $kul_verbose_level -eq 2 ]; then
echo -e "Success" | tee -a ${kul_log_file}
fi
else
echo -e "Fail" | tee -a ${kul_log_file}
#exit 1
fi
unset task_in
unset task_participant
# return errorcount
if [[ ! -z $total_errorcount ]]; then
total_errorcount=$(($total_errorcount + $errorcount))
if [ $kul_verbose_level -eq 2 ]; then
echo -e "total_errorcount: $total_errorcount\n\n\n"
fi
fi
}
# MAIN FUNCTION - kul_echo ######################################################################################
# echo loud or silent
function kul_echo {
local info_to_log=$1
#echo "previous verbose_level: $verbose_level"
if [[ -z "$verbose_level" ]]; then
#echo "setting verbose_level = 2"
verbose_level=2
fi
#if [ $silent -eq 0 ];then
# echo $1
#fi
if [ $verbose_level -eq 1 ]; then
#echo "log: $log"
echo ${info_to_log[@]} >> ${log}
elif [ $verbose_level -eq 2 ]; then
echo ${info_to_log[@]} | tee -a ${log}
fi
}
# MAIN FUNCTION - function kul_e2cl to echo to console & log file with matlab tic/toc behavior ##################
# parameters for logging
log_every_seconds=120
function kul_e2cl {
x=0
if [ -z ${elapsed_s+x} ]; then
#echo "var is unset"
elapsed_s=0
old_elapsed_s=0
fi
local old_elapsed_s=$elapsed_s
#local b=$(tput bold)
#local n=$(tput sgr0)
local b=''
local n=''
# calculate time in minutes since start of the script
now=$(date +%s)
elapsed_s=$(($now-$start))
elapsed_m=$(echo "scale=2; $elapsed_s/60" | bc) # use bc to get it in float minutes
diff_s=$(($elapsed_s-$old_elapsed_s))
diff_m=$(echo "scale=2; $diff_s/60" | bc) # use bc to get it in float minutes
if [ "$diff_s" -gt $log_every_seconds ]; then
echo " computation took ${diff_m} minutes ${b}(since start: ${elapsed_m} minutes)${n}"
echo " computation took ${diff_m} minutes (since start: ${elapsed_m})" >> $2
fi
# now do the logging
echo "${b}$1${n}"
echo $1 >> $2
}
function KUL_check_participant {
#echo ${cwd}/BIDS/sub-${participant}
if [ ! -d ${cwd}/BIDS/sub-${participant} ]; then
echo "Error: participant ${participant} does not exists."
exit 1
fi
}
### MAIN ############################################################################################
# Upon sourcing this script these variables are set
kul_main_dir=$(dirname "$0")
cwd=$(pwd)
script_start_time=$SECONDS
# The KUL_DEBUG variable
# export KUL_DEBUG=1 in terminal to debug
if [[ -z "$KUL_DEBUG" ]]; then
KUL_DEBUG=0
elif [ $KUL_DEBUG -eq 1 ]; then
echo "KUL_DEBUG is set to $KUL_DEBUG"
elif [ $KUL_DEBUG -gt 1 ]; then
echo "KUL_DEBUG is now set to $KUL_DEBUG"
set -x
fi
machine_type=$(uname)
#echo $machine_type
# -- Set global defaults --
#silent=1
#tmp=/tmp
# -- Execute global startup --
# timestamp
start=$(date +%s)
# Define directory/files to log in
log_dir=${cwd}/KUL_LOG/$script
d=$(date "+%Y-%m-%d_%H-%M-%S")
log=$log_dir/main_log_${d}.txt
# create preprocessing & log directory/files
if [ ! -z "$1" ];then
mkdir -p $log_dir
# -- Say Welcome --
command_line_options=$@
#if []
echo "Welcome to $script, version $version, invoked with parameters $command_line_options"
fi
# Check the mrtrix3 version
mrtrix_version_major=$(mrconvert | head -1 | cut -d'.' -f1 | cut -d' ' -f2)
mrtrix_version_minor=$(mrconvert | head -1 | cut -d'.' -f2)
mrtrix_version_revision_major=$(mrconvert | head -1 | cut -d'.' -f3 | cut -d'-' -f 1)
mrtrix_version_revision_minor=$(mrconvert | head -1 | cut -d'-' -f2)
if [ $mrtrix_version_revision_major -eq 2 ]; then
mrtrix3new=0
kul_echo "you are using an older version of MRTrix3 $mrtrix_version_revision_major"
kul_echo "this is not supported. Exiting"
exit 1
elif [ $mrtrix_version_revision_major -eq 3 ] && [ $mrtrix_version_revision_minor -lt 200 ]; then
mrtrix3new=1
kul_echo "you are using a new version of MRTrix3 $mrtrix_version_revision_major $mrtrix_version_revision_minor but not the latest"
elif [ $mrtrix_version_revision_major -ge 3 ] && [ $mrtrix_version_revision_minor -gt 200 ]; then
mrtrix3new=2
kul_echo "you are using the newest version of MRTrix3 $mrtrix_version_revision_major $mrtrix_version_revision_minor"
elif [ $mrtrix_version_revision_major -ge 3 ]; then
Has_legacy=$(dwi2mask | head -18 | grep legacy | rev | cut -d "," -f3 | rev)
if [ ! -z ${Has_legacy} ]; then
mrtrix3new=2
kul_echo "you are using the newest version of MRTrix3 $mrtrix_version_revision_major $mrtrix_version_revision_minor"
fi
else
kul_echo "cannot find correct mrtrix versions - exitting"
exit 1
fi