Skip to content

Commit

Permalink
🎨 Replace print with logger.* or raise Exception
Browse files Browse the repository at this point in the history
  • Loading branch information
shnizzedy committed Feb 14, 2024
1 parent 8f368de commit 43f5f46
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 24 deletions.
54 changes: 42 additions & 12 deletions CPAC/utils/create_flame_model_files.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# Copyright (C) 2016-2024 C-PAC Developers

# This file is part of C-PAC.

# C-PAC is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.

# C-PAC is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with C-PAC. If not, see <https://www.gnu.org/licenses/>.
from CPAC.utils.monitoring.custom_logging import getLogger

logger = getLogger("nipype.workflow")


def create_dummy_string(length):
ppstring = ""
for i in range(0, length):
Expand Down Expand Up @@ -126,6 +147,8 @@ def create_fts_file(ftest_list, con_names, model_name, current_output, out_dir):

import numpy as np

logger.info("\nFound f-tests in your model, writing f-tests file (.fts)..\n")

try:
out_file = os.path.join(out_dir, model_name + ".fts")

Expand Down Expand Up @@ -202,7 +225,8 @@ def create_con_ftst_file(
evs = evs.rstrip("\r\n").split(",")

if evs[0].strip().lower() != "contrasts":
raise Exception
msg = "first cell in contrasts file should contain 'Contrasts'"
raise ValueError(msg)

# remove "Contrasts" label and replace it with "Intercept"
# evs[0] = "Intercept"
Expand All @@ -217,7 +241,8 @@ def create_con_ftst_file(
try:
contrasts_data = np.genfromtxt(con_file, names=True, delimiter=",", dtype=None)
except:
raise Exception
msg = f"Could not successfully read in contrast file: {con_file}"
raise OSError(msg)

lst = contrasts_data.tolist()
# lst = list of rows of the contrast matrix (each row represents a
Expand Down Expand Up @@ -291,27 +316,31 @@ def create_con_ftst_file(
fts_n = fts_columns.T

if len(column_names) != (num_EVs_in_con_file):
"\n\n[!] CPAC says: The number of EVs in your model " "design matrix (found in the %s.mat file) does not " "match the number of EVs (columns) in your custom " "contrasts matrix CSV file.\n\nCustom contrasts matrix " "file: %s\n\nNumber of EVs in design matrix: %d\n" "Number of EVs in contrasts file: %d\n\nThe column " "labels in the design matrix should match those in " "your contrasts .CSV file.\nColumn labels in design " "matrix:\n%s" % (
logger.error(
"\n\n[!] CPAC says: The number of EVs in your model design matrix (found"
" in the %s.mat file) does not match the number of EVs (columns) in your"
" custom contrasts matrix CSV file.\n\nCustom contrasts matrix file:"
" %s\n\nNumber of EVs in design matrix: %d\nNumber of EVs in contrasts"
" file: %d\n\nThe column labels in the design matrix should match those in"
"your contrasts .CSV file.\nColumn labels in design matrix:\n%s",
model_name,
con_file,
len(column_names),
num_EVs_in_con_file,
str(column_names),
)

# raise Exception(err_string)
return None, None

for design_mat_col, con_csv_col in zip(column_names, evs[1:]):
if con_csv_col not in design_mat_col:
errmsg = (
"\n\n[!] CPAC says: The names of the EVs in your "
"custom contrasts .csv file do not match the names or "
"order of the EVs in the design matrix. Please make "
"sure these are consistent.\nDesign matrix EV columns: "
"%s\nYour contrasts matrix columns: %s\n\n" % (column_names, evs[1:])
logger.error(
"\n\n[!] CPAC says: The names of the EVs in your custom contrasts .csv"
" file do not match the names or order of the EVs in the design"
" matrix. Please make sure these are consistent.\nDesign matrix EV"
" columns: %s\nYour contrasts matrix columns: %s\n\n",
column_names,
evs[1:],
)

return None, None

out_file = os.path.join(output_dir, model_name + ".con")
Expand Down Expand Up @@ -344,6 +373,7 @@ def create_con_ftst_file(

ftest_out_file = None
if fTest:
logger.info("\nFound f-tests in your model, writing f-tests file (.fts)..\n")
ftest_out_file = os.path.join(output_dir, model_name + ".fts")

with open(ftest_out_file, "wt") as f:
Expand Down
28 changes: 25 additions & 3 deletions CPAC/utils/create_fsl_flame_preset.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
# Copyright (C) 2018-2024 C-PAC Developers

# This file is part of C-PAC.

# C-PAC is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.

# C-PAC is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with C-PAC. If not, see <https://www.gnu.org/licenses/>.
from CPAC.utils.monitoring.custom_logging import getLogger

logger = getLogger("nipype.workflow")

# TODO: create a function that can help easily map raw pheno files that do not
# TODO: have the participant_session id that CPAC uses

Expand Down Expand Up @@ -56,7 +76,7 @@ def write_group_list_text_file(group_list, out_file=None):
f.write(f"{part_id}\n")

if os.path.exists(out_file):
pass
logger.info("Group-level analysis participant list written:\n%s\n", out_file)

return out_file

Expand All @@ -83,7 +103,7 @@ def write_dataframe_to_csv(matrix_df, out_file=None):
matrix_df.to_csv(out_file, index=False)

if os.path.exists(out_file):
pass
logger.info("CSV file written:\n%s\n", out_file)


def write_config_dct_to_yaml(config_dct, out_file=None):
Expand Down Expand Up @@ -170,7 +190,9 @@ def write_config_dct_to_yaml(config_dct, out_file=None):
)

if os.path.exists(out_file):
pass
logger.info(
"Group-level analysis configuration YAML file written:\n%s\n", out_file
)


def create_design_matrix_df(
Expand Down
89 changes: 80 additions & 9 deletions CPAC/utils/create_fsl_model.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# Copyright (C) 2012-2024 C-PAC Developers

# This file is part of C-PAC.

# C-PAC is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.

# C-PAC is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with C-PAC. If not, see <https://www.gnu.org/licenses/>.
from CPAC.utils.monitoring.custom_logging import getLogger

logger = getLogger("nipype.workflow")


def load_pheno_file(pheno_file):
import os

Expand Down Expand Up @@ -362,7 +383,13 @@ def model_group_var_separately(
grouping_var, formula, pheno_data_dict, ev_selections, coding_scheme
):
if grouping_var is None or grouping_var not in formula:
raise Exception
msg = (
"\n\n[!] CPAC says: Model group variances separately is enabled, but the"
" grouping variable set is either set to None, or was not included in the"
f" model as one of the EVs.\n\nDesign formula: {formula}\nGrouping"
f" variable: {grouping_var}\n\n"
)
raise ValueError(msg)

# do this a little early for the grouping variable so that it doesn't
# get in the way of doing this for the other EVs once they have the
Expand Down Expand Up @@ -471,18 +498,33 @@ def model_group_var_separately(
def check_multicollinearity(matrix):
import numpy as np

logger.info("\nChecking for multicollinearity in the model..")

U, s, V = np.linalg.svd(matrix)

max_singular = np.max(s)
min_singular = np.min(s)

logger.info(
"Max singular: %s\nMin singular: %s\nRank: %s\n\n",
max_singular,
min_singular,
np.linalg.matrix_rank(matrix),
)

_warning = (
"[!] CPAC warns: Detected multicollinearity in the computed group-level"
" analysis model. Please double-check your model design.\n\n"
)

if min_singular == 0:
pass
logger.warning(_warning)

else:
condition_number = float(max_singular) / float(min_singular)
logger.info("Condition number: %f\n\n", condition_number)
if condition_number > 30:
pass
logger.warning(_warning)


def write_mat_file(
Expand Down Expand Up @@ -805,8 +847,17 @@ def create_design_matrix(
try:
dmatrix = patsy.dmatrix(formula, pheno_data_dict, NA_action="raise")

except:
raise Exception
except Exception as e:
msg = (
"\n\n[!] CPAC says: Design matrix creation wasn't successful - do the"
" terms in your formula correctly correspond to the EVs listed in your"
" phenotype file?\nPhenotype file provided: %s\n\nPhenotypic data"
" columns (regressors): %s\nFormula: %s\n\n",
pheno_file,
list(pheno_data_dict.keys()),
formula,
)
raise RuntimeError(msg) from e

# check the model for multicollinearity - Patsy takes care of this, but
# just in case
Expand Down Expand Up @@ -976,6 +1027,8 @@ def create_dummy_string(length):
def create_con_file(con_dict, col_names, file_name, current_output, out_dir):
import os

logger.info("col names: %s", col_names)

with open(os.path.join(out_dir, file_name) + ".con", "w+") as f:
# write header
num = 1
Expand Down Expand Up @@ -1012,6 +1065,7 @@ def create_fts_file(ftest_list, con_dict, model_name, current_output, out_dir):
import numpy as np

try:
logger.info("\nFound f-tests in your model, writing f-tests file (.fts)..\n")
with open(os.path.join(out_dir, model_name + ".fts"), "w") as f:
print("/NumWaves\t", len(con_dict), file=f)
print("/NumContrasts\t", len(ftest_list), file=f)
Expand Down Expand Up @@ -1089,6 +1143,7 @@ def create_con_ftst_file(
# evs[0] = "Intercept"

fTest = False
logger.info("evs: %s", evs)
for ev in evs:
if "f_test" in ev:
count_ftests += 1
Expand All @@ -1099,8 +1154,9 @@ def create_con_ftst_file(
try:
data = np.genfromtxt(con_file, names=True, delimiter=",", dtype=None)

except:
raise Exception
except Exception as e:
msg = f"Error: Could not successfully read in contrast file: {con_file}"
raise OSError(msg) from e

lst = data.tolist()

Expand Down Expand Up @@ -1218,6 +1274,7 @@ def create_con_ftst_file(
np.savetxt(f, contrasts, fmt="%1.5e", delimiter="\t")

if fTest:
logger.info("\nFound f-tests in your model, writing f-tests file (.fts)..\n")
ftest_out_dir = os.path.join(output_dir, model_name + ".fts")

with open(ftest_out_dir, "wt") as f:
Expand Down Expand Up @@ -1361,8 +1418,13 @@ def run(
try:
if not os.path.exists(output_dir):
os.makedirs(output_dir)
except:
raise Exception
except Exception as e:
msg = (
"\n\n[!] CPAC says: Could not successfully create the group analysis"
f" output directory:\n{output_dir}\n\nMake sure you have write access"
" in this file structure.\n\n\n"
)
raise OSError(msg) from e

measure_dict = {}

Expand Down Expand Up @@ -1551,6 +1613,10 @@ def run(
or (custom_contrasts == "")
or ("None" in custom_contrasts)
):
logger.info(
"Writing contrasts file (.con) based on contrasts provided using the group"
" analysis model builder's contrasts editor.."
)
create_con_file(
contrasts_dict, regressor_names, model_name, current_output, model_out_dir
)
Expand All @@ -1561,6 +1627,11 @@ def run(
)

else:
logger.info(
"\nWriting contrasts file (.con) based on contrasts provided with a custom"
" contrasts matrix CSV file..\n"
)

create_con_ftst_file(
custom_contrasts,
model_name,
Expand Down

0 comments on commit 43f5f46

Please sign in to comment.