File size: 11,614 Bytes
093748c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import sys
import colorama
import pathvalidate
import os
import re

from pathlib import Path
from config import App
from colorama import Fore
from misc.enums import Mode, ModelType, LabelType

modes = ["optimize-architecture", "training", "predict"]
RED = "\033[31m"
config = App.config()


def validate_config():
    # we need this for color coded print statements
    colorama.init(autoreset=True)

    if not is_valid_config():
        sys.exit("Config is invalid. Please provide a valid config file.")
    print("Config file is valid")


def select_mode_from_config():
    general_section = config["DEFAULT"]
    mode = general_section["mode"].lower()
    match mode:
        case "predict":
            return Mode.PREDICT
        case "training":
            return Mode.TRAIN
        case "optimize-architecture":
            return Mode.OPTIMIZE


def select_model_type_from_config():
    # we need this for color coded print statements
    colorama.init(autoreset=True)

    model_section = config["MODEL"]
    model = model_section["model_type"].lower()
    match model:
        case "gcnconv":
            return ModelType.GCNCONV
        case "sageconv":
            return ModelType.SAGECONV
        case "sageconvmlp":
            return ModelType.SAGECONVMLP
        case "sageconvgatmlp":
            return ModelType.SAGECONVGATMLP


def is_valid_config():
    # No sections => File doesn't exist or is missing sections
    if len(config.sections()) == 0:
        print("Config file not found or empty")
        return False

    # Return False if any section in general is not filled out with a valid option
    general_section = config["DEFAULT"]
    if general_section["mode"].lower() not in map(lambda x: x.lower(), modes):
        print(f"Config file does not specify a valid mode. Please select one of the following: "
              f"{modes}")
        return False

    paths_section = config["FILE_PATHS"]
    # check if result_dir path is a valid file path
    if not pathvalidate.is_valid_filepath(paths_section["result_dir"], platform="auto"):
        print(Fore.RED + f"WARNING: File {paths_section.get('result_dir')} is not a valid path")
        return False
    else:
        path = Path(paths_section["result_dir"])
        # check if result_dir already exists. If yes, warn user that previous results could be overwritten, else,
        # create folder
        if path.exists():
            print(Fore.RED + f"WARNING: Path {paths_section.get('result_dir')} already exists. Previous results may "
                             f"be overwriten")
        else:
            Path(path).mkdir(parents=True, exist_ok=True)
    # check if embeddings path is a valid file path
    if not pathvalidate.is_valid_filepath(paths_section["embeddings"], platform="auto"):
        print(Fore.RED + f"WARNING: File {paths_section.get('embeddings')} is not a valid path")
        return False
    # check if embeddings path exists
    if not Path(paths_section["embeddings"]).exists():
        print(Fore.RED + f"WARNING: File {paths_section.get('embeddings')} does not exist")
        return False
    # check if structure path is a valid file path
    if not pathvalidate.is_valid_filepath(paths_section["3d_structure_dir"], platform="auto"):
        print(Fore.RED + f"WARNING: File {paths_section.get('3d_structure_dir')} is not a valid path")
        return False
    # check if structure path exists
    if not Path(paths_section["3d_structure_dir"]).exists():
        print(Fore.RED + f"WARNING: File {paths_section.get('3d_structure_dir')} does not exist")
        return False

    model_section = config["MODEL"]
    # check if cutoff is a number smaller 1
    if not model_section.getfloat('cutoff') < 1.0:
        print(Fore.RED + f"WARNING: Cutoff {model_section.getfloat('cutoff')} is not a valid cutoff. "
                         f"Set cutoff to a value between 0 and 1")
        return False

    return True


def get_id_list_path():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('id_list'))


def get_embeddings_path():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('embeddings'))


def get_sequence_path():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('fasta_file_path'))


def get_3d_structure_dir():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('3d_structure_dir'))


def get_DSSP_dir():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('precomputed_DSSP_feature_dir'))


def get_result_dir():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('result_dir'))


def get_cache_dir():
    paths_section = config["FILE_PATHS"]
    return Path(paths_section.get('cache_folder'))


def get_cv_splits():
    cv_split_ids = []
    paths_section = config["FILE_PATHS"]
    cv_split_folder = Path(paths_section.get('cv_split_id_files_folder'))
    cv_split_files = os.listdir(cv_split_folder)

    for file in cv_split_files:
        cv_split = []
        with open(os.path.join(cv_split_folder, file), 'r') as fh:
            lines = fh.readlines()
            for line in lines:
                protein_id = line.strip()
                if protein_id != "":
                    cv_split.append(protein_id)
            cv_split_ids.append(cv_split)

    return cv_split_ids


def get_label_path(label_type):
    label_section = config["LABELS"]
    match label_type:
        case LabelType.METAL:
            return Path(label_section.get('metal_label_file'))
        case LabelType.SMALL:
            return Path(label_section.get('small_label_file'))
        case LabelType.NUCLEAR:
            return Path(label_section.get('nuclear_label_file'))


def do_logging():
    utility_section = config["UTILITY"]
    return utility_section.getboolean("do_logging")


def use_cache():
    utility_section = config["UTILITY"]
    return utility_section.getboolean("use_cache")


def get_weight_dir():
    model_section = config["MODEL"]
    return Path(model_section.get('weight_folder'))


def get_in_channels():
    model_section = config["MODEL"]
    return model_section.getint('in_channels')


def get_additional_channels():
    model_section = config["MODEL"]
    return model_section.getint('nr_additional_features')


def use_dssp():
    model_section = config["MODEL"]
    return model_section.getboolean('use_dssp')


def get_out_channels():
    model_section = config["MODEL"]
    return model_section.getint('out_channels')


def get_cutoff():
    model_section = config["MODEL"]
    return model_section.getfloat('cutoff')


def use_postprocessing():
    postprocessing_section = config["POSTPROCESSING"]
    return postprocessing_section.getboolean('use_postprocessing')


def get_rASA_cutoff():
    postprocessing_section = config["POSTPROCESSING"]
    return postprocessing_section.getfloat('rASA_cutoff')


def get_site_cutoff():
    postprocessing_section = config["POSTPROCESSING"]
    return postprocessing_section.getint('binding_site_proximity')


def get_output_file_name():
    output_section = config["OUTPUT"]
    return output_section.get('output_file_name')


def write_ri():
    output_section = config["OUTPUT"]
    return output_section.getboolean('write_ri')


def get_feature_channels(only_first_value=False):
    training_section = config["MODEL_PARAMETERS"]
    feature_list = [int(item) for item in training_section.get('features').split(',')]
    if not only_first_value:
        return feature_list
    else:
        return feature_list[0]


def get_dropouts(only_first_value=False):
    training_section = config["MODEL_PARAMETERS"]
    dropout_list = [float(item) for item in training_section.get('dropout').split(',')]
    if not only_first_value:
        return dropout_list
    else:
        return dropout_list[0]


def get_batch_size(only_first_value=False):
    training_section = config["MODEL_PARAMETERS"]
    batch_size_list = [int(item) for item in training_section.get('batchsize').split(',')]
    if not only_first_value:
        return batch_size_list
    else:
        return batch_size_list[0]


def get_epochs(only_first_value=False):
    training_section = config["MODEL_PARAMETERS"]
    epochs_list = [int(item) for item in training_section.get('epochs').split(',')]
    if not only_first_value:
        return epochs_list
    else:
        return epochs_list[0]


def is_early_stopping():
    training_section = config["MODEL_PARAMETERS"]
    return training_section.getboolean("early_stopping")


def get_weights(only_first_value=False):
    training_section = config["LOSS_FUNCTION_PARAMETERS"]
    weights_list = [[float(weight) for weight in item.split(',')] for item in re.findall(r'\[(.*?)\]', training_section.get('weights'))]
    if not only_first_value:
        return weights_list
    else:
        return weights_list[0]


def get_structure_cutoff(only_first_value=False):
    training_section = config["DATASET"]
    structure_cutoff_list = [int(item) for item in training_section.get('cutoff_structure').split(',')]
    if not only_first_value:
        return structure_cutoff_list
    else:
        return structure_cutoff_list[0]


def get_activation():
    training_section = config["MODEL_PARAMETERS"]
    return eval(training_section.get("activation"))


def get_activation_as_string():
    training_section = config["MODEL_PARAMETERS"]
    return training_section.get("activation")


def get_dropouts_fcn(only_first_value=False):
    training_section = config["MODEL_PARAMETERS"]
    dropout_fcn_list = [float(item) for item in training_section.get('dropout_fcn').split(',')]
    if not only_first_value:
        return dropout_fcn_list
    else:
        return dropout_fcn_list[0]


def get_optimizer_arguments(only_first_value=False):
    optimizer_section = config["OPTIMIZER_PARAMETERS"]
    learning_rates = [float(item) for item in optimizer_section.get('learning_rate').split(',')]
    betas = [[float(beta) for beta in item.split(',')] for item in re.findall(r'\[(.*?)\]', optimizer_section.get('betas'))]
    epsilons = [float(item) for item in optimizer_section.get('epsilon').split(',')]
    weight_decays = [float(item) for item in optimizer_section.get('weight_decay').split(',')]
    if not only_first_value:
        optimizer_arguments = {
            "lr": learning_rates,
            "betas": betas,
            "eps": epsilons,
            "weight_decay": weight_decays
        }
    else:
        # TODO: implement usage of this in training loop (currently always only taking first value)
        optimizer_arguments = {
            "lr": learning_rates[0],
            "betas": betas[0],
            "eps": epsilons[0],
            "weight_decay": weight_decays[0]
        }
    return optimizer_arguments


def get_model_parameter_dict(only_first_value=False):
    model_parameter_dict = {
        "cutoff": get_cutoff(),
        "in_channels": get_in_channels(),
        "out_channels": get_out_channels(),
        "features": get_feature_channels(only_first_value),
        "dropout": get_dropouts(only_first_value),
        "epochs": get_epochs(only_first_value),
        "early_stopping": is_early_stopping(),
        "weights": get_weights(only_first_value),
        "cutoff_structure": get_structure_cutoff(only_first_value),
        "activation": get_activation_as_string(),
        "batchsize": get_batch_size(only_first_value),
        "droupout_fcn": get_dropouts_fcn(only_first_value),
        "use_dssp": use_dssp(),
        "nr_dssp_features": get_additional_channels()
    }
    return model_parameter_dict