66from Bio .Seq import Seq
77import subprocess
88import sys
9+ import argparse
910
1011def one_hot_encode (seq ):
1112 mapping = {'A' : 0 , 'C' : 1 , 'G' : 2 , 'T' : 3 } # Mapping of nucleotides to integers
@@ -37,37 +38,41 @@ def find_orfs(sequence, chosen_length):
3738
3839 orfs_tensor = torch .stack (orfs , dim = 0 ) # Stack the ORFs along a new dimension
3940 orfs_tensor = orfs_tensor .unsqueeze (0 ) # Add an extra dimension at the beginning for batch size
40- orfs_tensor = orfs_tensor .permute (0 , 3 , 1 , 2 ) # Permute the dimensions to get to the required size
41+ orfs_tensor = orfs_tensor .permute (0 , 3 , 2 , 1 ) # Permute the dimensions to get to the required size
42+ orfs_tensor = orfs_tensor .float ()
4143
4244 return orfs_seq , orfs_tensor
4345
4446def prediction (fastq_file_path ,precision_thresh , damage , threshold_seq_length , save_dir ):
4547 damage_list = ["nodam" , "middam" , "highdam" ]
4648 possible_seq_length = [32 , 35 , 38 , 41 ]
49+ dir_path = os .path .dirname (os .path .abspath (__file__ ))
4750 assert os .path .isfile (fastq_file_path ), "The give file path does not exist"
4851 assert isinstance (precision_thresh , float ), "Please enter your precision threshold as float"
4952 assert damage in damage_list , "Please enter for the degree of damage nodam, middam or highdam"
5053 assert threshold_seq_length in possible_seq_length , "Please enter a valid threshold for the sequences. So far these are: " + str (possible_seq_length
5154 )
5255 assert os .path .isdir (save_dir ), "Please enter a valid directory to save the output files"
5356 trained_seq_length = threshold_seq_length - 2
54- weights_path = os .path .join ("~" , "src" , "model_weights" , f"{ damage } _{ trained_seq_length } nt.pth" )
57+ weights_path = os .path .join (dir_path , "model_weights" , f"{ damage } _{ trained_seq_length } nt.pth" )
5558 model = TheOneAndOnly (channels = 4 ,
5659 test = False )
5760 pretrained_weights = torch .load (weights_path ,
5861 map_location = torch .device ('cpu' ))
5962 pretrained_weights = {k .replace ("module." , "" ): v for k , v in pretrained_weights .items ()}
63+ model .eval ()
6064 predicted_sequences = []
6165 discarded_sequences = []
66+ input_length_model = threshold_seq_length - 2
6267 with open (fastq_file_path , "r" ) as handle :
6368 # Iterate over each sequence record in the file
6469 for record in SeqIO .parse (handle , "fastq" ):
6570 # Access the sequence and quality scores
66- if len (record .seq ) >= threshold_seq_length :
71+ if len (record .seq ) > threshold_seq_length :
6772 sequence = record .seq
6873 sequence = sequence [:threshold_seq_length ]
6974 id_seq = record .id
70- orfs_seq , orfs_tensor = find_orfs (sequence , 30 )
75+ orfs_seq , orfs_tensor = find_orfs (sequence , input_length_model )
7176 model_output = model (orfs_tensor )
7277 index_correct = model_output .argmax ().item ()
7378 max_item = model_output .max ()
@@ -99,12 +104,27 @@ def prediction(fastq_file_path,precision_thresh, damage, threshold_seq_length, s
99104
100105 with open (disc_orfs_path , "w" ) as output_handle :
101106 SeqIO .write (discarded_sequences , output_handle , "fasta" )
102- subprocess .run (['gzip' , "f" , corr_orfs_path ])
103- subprocess .run (['gzip' , "f" , disc_orfs_path ])
104-
105- fastq_file_path = sys .argv [1 ]
106- precision_thresh = float (sys .argv [2 ])
107- damage = sys .argv [3 ]
108- threshold_seq_length = int (sys .argv [4 ])
109- save_dir = sys .argv [5 ]
107+ # subprocess.run(['gzip', "f", corr_orfs_path])
108+ # subprocess.run(['gzip', "f", disc_orfs_path])
109+
110+
111+
112+
113+
114+ parser = argparse .ArgumentParser (description = 'Predictor' )
115+
116+ # Add arguments to the parser
117+ parser .add_argument ('fastq_file_path' ,type = str , help = 'Path to the fastq file' )
118+ parser .add_argument ('--precision_thresh' , type = float , default = 0.01 , help = "The threshold for the minimum certainty of the model to accept an open reading frame. Input type is a float in range 0 < x < 1 Default is 0.01." )
119+ parser .add_argument ('--damage' , default = 'nodam' , help = 'Degree of damage' )
120+ parser .add_argument ('--threshold_seq_length' , type = int , default = 32 , help = ' The minimum sequence length as input for the model. All reads with a lower length will filtered and saved in _discORFs.' )
121+ parser .add_argument ('--save_dir' , default = os .getcwd (), help = 'Directory to save output files' )
122+ args = parser .parse_args ()
123+
124+ fastq_file_path = args .fastq_file_path
125+ precision_thresh = args .precision_thresh
126+ damage = args .damage
127+ threshold_seq_length = args .threshold_seq_length
128+ save_dir = args .save_dir
129+
110130prediction (fastq_file_path , precision_thresh , damage , threshold_seq_length , save_dir )
0 commit comments