11import argparse
2- import datetime
32import importlib .util
43import json
54import logging
2019from syncropatch_export .voltage_protocols import VoltageProtocol
2120
2221from pcpostprocess .detect_ramp_bounds import detect_ramp_bounds
22+ from pcpostprocess .directory_builder import setup_output_directory
2323from pcpostprocess .hergQC import hERGQC
2424from pcpostprocess .infer_reversal import infer_reversal_potential
2525from pcpostprocess .leak_correct import fit_linear_leak , get_leak_corrected
@@ -45,7 +45,7 @@ def main():
4545 parser = argparse .ArgumentParser ()
4646 parser .add_argument ('data_directory' )
4747 parser .add_argument ('-c' , '--no_cpus' , default = 1 , type = int )
48- parser .add_argument ('--output_dir' )
48+ parser .add_argument ('--output_dir' , default = "output" )
4949 parser .add_argument ('-w' , '--wells' , nargs = '+' )
5050 parser .add_argument ('--protocols' , nargs = '+' )
5151 parser .add_argument ('--reversal_spread_threshold' , type = float , default = 10 )
@@ -62,19 +62,7 @@ def main():
6262
6363 logging .basicConfig (level = args .log_level )
6464
65- if args .output_dir is None :
66- args .output_dir = os .path .join ('output' , 'hergqc' )
67-
68- if not os .path .exists (args .output_dir ):
69- os .makedirs (args .output_dir )
70-
71- with open (os .path .join (args .output_dir , 'info.txt' ), 'w' ) as description_fout :
72- git_hash = get_git_revision_hash ()
73- datetimestr = str (datetime .datetime .now ())
74- description_fout .write (f"Date: { datetimestr } \n " )
75- description_fout .write (f"Commit { git_hash } \n " )
76- command = " " .join (sys .argv )
77- description_fout .write (f"Command: { command } \n " )
65+ output_dir = setup_output_directory (args .output_dir , "run_herg_qc" )
7866
7967 spec = importlib .util .spec_from_file_location (
8068 'export_config' ,
@@ -107,7 +95,7 @@ def main():
10795 sys .modules ['export_config' ] = export_config
10896 spec .loader .exec_module (export_config )
10997
110- export_config .savedir = args . output_dir
98+ export_config .savedir = output_dir
11199
112100 args .saveID = export_config .saveID
113101 args .savedir = export_config .savedir
@@ -181,7 +169,9 @@ def main():
181169 ** pool_kws ) as pool :
182170
183171 pool_argument_list = zip (readnames , savenames , times_list ,
184- [args for i in readnames ])
172+ [args for i in readnames ],
173+ [output_dir for i in readnames ])
174+
185175 well_selections , qc_dfs = \
186176 list (zip (* pool .starmap (run_qc_for_protocol , pool_argument_list )))
187177
@@ -193,17 +183,17 @@ def main():
193183 times = sorted (res_dict [protocol ])
194184 if len (times ) == 4 :
195185 qc3_bookend_dict = qc3_bookend (protocol , savename ,
196- times , args )
186+ times , args , wells , output_dir )
197187 else :
198188 qc3_bookend_dict = {well : True for well in qc_df .well .unique ()}
199189
200190 qc_df ['qc3.bookend' ] = [qc3_bookend_dict [well ] for well in qc_df .well ]
201191
202- savedir = args . output_dir
192+ savedir = output_dir
203193 saveID = export_config .saveID
204194
205- if not os .path .exists (os .path .join (args . output_dir , savedir )):
206- os .makedirs (os .path .join (args . output_dir , savedir ))
195+ if not os .path .exists (os .path .join (output_dir , savedir )):
196+ os .makedirs (os .path .join (output_dir , savedir ))
207197
208198 # qc_df will be updated and saved again, but it's useful to save them here for debugging
209199 # Write qc_df to file
@@ -282,7 +272,8 @@ def main():
282272
283273 args_list = list (zip (readnames , savenames , times_list , [wells_to_export ] *
284274 len (savenames ),
285- [args for i in readnames ]))
275+ [args for i in readnames ],
276+ [output_dir for i in readnames ]))
286277
287278 with multiprocessing .Pool (min (args .no_cpus , no_protocols ),
288279 ** pool_kws ) as pool :
@@ -344,7 +335,7 @@ def main():
344335
345336 chrono_dict = {times [0 ]: prot for prot , times in zip (savenames , times_list )}
346337
347- with open (os .path .join (args . output_dir , 'chrono.txt' ), 'w' ) as fout :
338+ with open (os .path .join (output_dir , 'chrono.txt' ), 'w' ) as fout :
348339 for key in sorted (chrono_dict ):
349340 val = chrono_dict [key ]
350341 # Output order of protocols
@@ -382,8 +373,8 @@ def main():
382373
383374 qc_styled_df = create_qc_table (qc_df )
384375 logging .info (qc_styled_df )
385- qc_styled_df .to_excel (os .path .join (args . output_dir , 'qc_table.xlsx' ))
386- qc_styled_df .to_latex (os .path .join (args . output_dir , 'qc_table.tex' ))
376+ qc_styled_df .to_excel (os .path .join (output_dir , 'qc_table.xlsx' ))
377+ qc_styled_df .to_latex (os .path .join (output_dir , 'qc_table.tex' ))
387378
388379 # Save in csv format
389380 qc_df .to_csv (os .path .join (savedir , 'QC-%s.csv' % saveID ))
@@ -395,11 +386,11 @@ def main():
395386 # Load only QC vals. TODO use a new variabile name to avoid confusion
396387 qc_vals_df = extract_df [['well' , 'sweep' , 'protocol' , 'Rseal' , 'Cm' , 'Rseries' ]].copy ()
397388 qc_vals_df ['drug' ] = 'before'
398- qc_vals_df .to_csv (os .path .join (args . output_dir , 'qc_vals_df.csv' ))
389+ qc_vals_df .to_csv (os .path .join (output_dir , 'qc_vals_df.csv' ))
399390
400- extract_df .to_csv (os .path .join (args . output_dir , 'subtraction_qc.csv' ))
391+ extract_df .to_csv (os .path .join (output_dir , 'subtraction_qc.csv' ))
401392
402- with open (os .path .join (args . output_dir , 'passed_wells.txt' ), 'w' ) as fout :
393+ with open (os .path .join (output_dir , 'passed_wells.txt' ), 'w' ) as fout :
403394 for well , passed in passed_qc_dict .items ():
404395 if passed :
405396 fout .write (well )
@@ -474,9 +465,9 @@ def agg_func(x):
474465 return ret_df
475466
476467
477- def extract_protocol (readname , savename , time_strs , selected_wells , args ):
468+ def extract_protocol (readname , savename , time_strs , selected_wells , args , savedir ):
478469 logging .info (f"extracting { savename } " )
479- savedir = args . output_dir
470+
480471 saveID = args .saveID
481472
482473 traces_dir = os .path .join (savedir , 'traces' )
@@ -607,8 +598,8 @@ def extract_protocol(readname, savename, time_strs, selected_wells, args):
607598 before_leak_currents = []
608599 after_leak_currents = []
609600
610- out_dir = os .path .join (savedir ,
611- f"{ saveID } -{ savename } -leak_fit-before" )
601+ out_path = os .path .join (savedir , "leak_correction" ,
602+ f"{ saveID } -{ savename } -leak_fit-before" )
612603
613604 for sweep in range (before_current .shape [0 ]):
614605 row_dict = {
@@ -630,14 +621,14 @@ def extract_protocol(readname, savename, time_strs, selected_wells, args):
630621 before_params , before_leak = fit_linear_leak (before_current [sweep , :],
631622 voltages , times ,
632623 * ramp_bounds ,
633- output_dir = out_dir ,
624+ output_dir = out_path ,
634625 save_fname = f"{ well } _sweep{ sweep } .png"
635626 )
636627
637628 before_leak_currents .append (before_leak )
638629
639- out_dir = os .path .join (savedir ,
640- f"{ saveID } -{ savename } -leak_fit-after" )
630+ out_path = os .path .join (savedir ,
631+ f"{ saveID } -{ savename } -leak_fit-after" )
641632 # Convert linear regression parameters into conductance and reversal
642633 row_dict ['gleak_before' ] = before_params [1 ]
643634 row_dict ['E_leak_before' ] = - before_params [0 ] / before_params [1 ]
@@ -646,7 +637,7 @@ def extract_protocol(readname, savename, time_strs, selected_wells, args):
646637 voltages , times ,
647638 * ramp_bounds ,
648639 save_fname = f"{ well } _sweep{ sweep } .png" ,
649- output_dir = out_dir )
640+ output_dir = out_path )
650641
651642 after_leak_currents .append (after_leak )
652643
@@ -687,7 +678,8 @@ def extract_protocol(readname, savename, time_strs, selected_wells, args):
687678 row_dict ['QC.Erev' ] = E_rev < - 50 and E_rev > - 120
688679
689680 # Check QC6 for each protocol (not just the staircase)
690- plot_dir = os .path .join (savedir , 'debug' )
681+ plot_dir = os .path .join (savedir , "QC" , "debug" ,
682+ f"debug_{ well } _{ savename } " )
691683
692684 if not os .path .exists (plot_dir ):
693685 os .makedirs (plot_dir )
@@ -743,11 +735,11 @@ def extract_protocol(readname, savename, time_strs, selected_wells, args):
743735 res = \
744736 get_time_constant_of_first_decay (subtracted_trace , times , desc ,
745737 args = args ,
746- output_path = os .path .join (args . output_dir ,
747- ' debug' ,
748- ' -120mV time constant' ,
738+ output_path = os .path .join (savedir ,
739+ " debug" ,
740+ " -120mV time constant" ,
749741 f"{ savename } -{ well } -sweep"
750- "{sweep}-time-constant-fit.pdf" ))
742+ f "{ sweep } -time-constant-fit.pdf" ))
751743
752744 row_dict ['-120mV decay time constant 1' ] = res [0 ][0 ]
753745 row_dict ['-120mV decay time constant 2' ] = res [0 ][1 ]
@@ -810,7 +802,7 @@ def extract_protocol(readname, savename, time_strs, selected_wells, args):
810802 return extract_df
811803
812804
813- def run_qc_for_protocol (readname , savename , time_strs , args ):
805+ def run_qc_for_protocol (readname , savename , time_strs , args , output_dir ):
814806 df_rows = []
815807
816808 assert len (time_strs ) == 2
@@ -836,7 +828,9 @@ def run_qc_for_protocol(readname, savename, time_strs, args):
836828 # Convert to s
837829 sampling_rate = before_trace .sampling_rate
838830
839- savedir = args .output_dir
831+ savedir = os .path .join (output_dir , "QC" )
832+ leak_correction_dir = os .path .join (savedir , "leak_correction" )
833+
840834 if not os .path .exists (savedir ):
841835 os .makedirs (savedir )
842836
@@ -910,14 +904,14 @@ def run_qc_for_protocol(readname, savename, time_strs, args):
910904 times ,
911905 * ramp_bounds ,
912906 save_fname = f"{ well } -sweep{ sweep } -before.png" ,
913- output_dir = savedir )
907+ output_dir = leak_correction_dir )
914908
915909 after_params1 , after_leak = fit_linear_leak (after_raw ,
916910 voltage ,
917911 times ,
918912 * ramp_bounds ,
919913 save_fname = f"{ well } -sweep{ sweep } -after.png" ,
920- output_dir = savedir )
914+ output_dir = leak_correction_dir )
921915
922916 before_currents_corrected [sweep , :] = before_raw - before_leak
923917 after_currents_corrected [sweep , :] = after_raw - after_leak
@@ -988,10 +982,13 @@ def run_qc_for_protocol(readname, savename, time_strs, args):
988982 return selected_wells , df
989983
990984
991- def qc3_bookend (readname , savename , time_strs , args ):
992- plot_dir = os .path .join (args . output_dir , args .savedir ,
985+ def qc3_bookend (readname , savename , time_strs , args , wells , output_dir ):
986+ plot_dir = os .path .join (output_dir , args .savedir ,
993987 f"{ args .saveID } -{ savename } -qc3-bookend" )
994988
989+ if not os .path .exists (plot_dir ):
990+ os .makedirs (plot_dir )
991+
995992 filepath_first_before = os .path .join (args .data_directory ,
996993 f"{ readname } _{ time_strs [0 ]} " )
997994 filepath_last_before = os .path .join (args .data_directory ,
@@ -1047,21 +1044,34 @@ def qc3_bookend(readname, savename, time_strs, args):
10471044 last_processed = {}
10481045
10491046 # Iterate over all wells
1050- for well in np .array (all_wells ).flatten ():
1047+ for well in np .array (wells ).flatten ():
10511048 first_before_current = first_before_current_dict [well ][0 , :]
10521049 first_after_current = first_after_current_dict [well ][0 , :]
10531050 last_before_current = last_before_current_dict [well ][- 1 , :]
10541051 last_after_current = last_after_current_dict [well ][- 1 , :]
10551052
1056- output_directory = os .path .join (args .output_dir , "leak_correction" )
10571053 save_fname = f"{ well } _{ savename } _before0.pdf"
10581054
1059- # Plot subtraction
1060- get_leak_corrected (first_before_current ,
1061- voltage , times ,
1062- * ramp_bounds ,
1063- save_fname = save_fname ,
1064- output_dir = output_directory )
1055+ if args .debug :
1056+ qc3_output_dir = os .path .join (output_dir ,
1057+ "QC" ,
1058+ "debug" ,
1059+ f"debug_{ well } _{ savename } " ,
1060+ "qc3_bookend" )
1061+
1062+ if not os .path .exists (qc3_output_dir ):
1063+ os .makedirs (qc3_output_dir )
1064+
1065+ leak_correct_dir = os .path .join (qc3_output_dir ,
1066+ "leak_correction" )
1067+
1068+ # Plot subtraction
1069+ if args .debug :
1070+ get_leak_corrected (first_before_current ,
1071+ voltage , times ,
1072+ * ramp_bounds ,
1073+ save_fname = save_fname ,
1074+ output_dir = leak_correct_dir )
10651075
10661076 before_traces_first [well ] = get_leak_corrected (first_before_current ,
10671077 voltage , times ,
@@ -1110,9 +1120,7 @@ def qc3_bookend(readname, savename, time_strs, args):
11101120
11111121 res_dict [well ] = passed
11121122
1113- save_fname = os .path .join (args .output_dir ,
1114- 'debug' ,
1115- f"debug_{ well } _{ savename } " ,
1123+ save_fname = os .path .join (output_dir ,
11161124 'qc3_bookend' )
11171125
11181126 ax .plot (times , trace1 )
0 commit comments