From 7631979d5311e225439fe1bdb3fc3282dc806c94 Mon Sep 17 00:00:00 2001 From: Jennings Zhang Date: Wed, 1 Nov 2023 15:55:59 -0400 Subject: [PATCH] Do thickness --- Dockerfile | 2 +- base/Dockerfile | 2 ++ base/build.sh | 2 +- gifit/__init__.py | 2 +- gifit/__main__.py | 42 +++++++++++++++++++++++++++++++++--------- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index b9bc04d..23aec03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/fnndsc/pl-gifit:base-1 +FROM docker.io/fnndsc/pl-gifit:base-2 LABEL org.opencontainers.image.authors="FNNDSC " \ org.opencontainers.image.title="pl-gifit" \ diff --git a/base/Dockerfile b/base/Dockerfile index bca4f76..ed2bd2b 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -14,6 +14,8 @@ RUN microminc.sh -p '&run' \ print_n_polygons \ volume_object_evaluate \ vertstats_math \ + cortical_thickness \ + average_surfaces \ /microminc # MNI data needs to be copied manually diff --git a/base/build.sh b/base/build.sh index 997a749..42eed6f 100755 --- a/base/build.sh +++ b/base/build.sh @@ -2,4 +2,4 @@ exec docker buildx build --push \ --platform linux/amd64,linux/arm64,linux/ppc64le \ - -t docker.io/fnndsc/pl-gifit:base-1 . + -t docker.io/fnndsc/pl-gifit:base-2 . diff --git a/gifit/__init__.py b/gifit/__init__.py index a28f9ae..5cd083d 100644 --- a/gifit/__init__.py +++ b/gifit/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.1.0' +__version__ = '0.2.0' DISPLAY_TITLE = r""" _ _ __ _ _ diff --git a/gifit/__main__.py b/gifit/__main__.py index 43cf444..59b7eee 100644 --- a/gifit/__main__.py +++ b/gifit/__main__.py @@ -8,7 +8,7 @@ from argparse import ArgumentParser, Namespace, ArgumentDefaultsHelpFormatter from concurrent.futures import ThreadPoolExecutor from pathlib import Path -from typing import Optional +from typing import Optional, Sequence from chris_plugin import chris_plugin, PathMapper from loguru import logger @@ -25,6 +25,8 @@ help='Name of built-in model to use, or a path to a custom CSV model.') parser.add_argument('-s', '--size', dest='size', type=int, default=81920, help='Output mesh size') +parser.add_argument('-t', '--thickness-fwhm', dest='thickness_fwhm', type=str, default='0,10', + help='List of fwhm values in mm to use for calculating thickness between surfaces') parser.add_argument('-V', '--version', action='version', version=f'%(prog)s {__version__}') parser.add_argument('-J', '--threads', type=int, default=0, @@ -51,17 +53,20 @@ def main(options: Namespace, inputdir: Path, outputdir: Path): model_file = options.model if os.path.isfile(options.model) else get_builtin_model(options.model) model = Model(model_file) + thickness_fwhm = __parse_thickness_fwhm(options.thickness_fwhm) + mapper = PathMapper.file_mapper(inputdir, outputdir, glob='**/*.mnc', suffix='.obj') with ThreadPoolExecutor(max_workers=nproc) as pool: - results = pool.map(lambda t, p, s: run_surface_fit(*t, p, s), mapper, + results = pool.map(lambda t, p, s, b: run_surface_fit(*t, p, s, b), mapper, itertools.repeat(model), - itertools.repeat(str(options.size))) + itertools.repeat(str(options.size)), + itertools.repeat(thickness_fwhm)) if not options.no_fail and not all(results): sys.exit(1) -def run_surface_fit(grid: Path, output_surf: Path, model: Model, size: str) -> bool: +def run_surface_fit(grid: Path, output_surf: Path, model: Model, size: str, thickness_fwhm: Sequence[int]) -> bool: """ :return: True if successful """ @@ -93,12 +98,23 @@ def run_surface_fit(grid: Path, output_surf: Path, model: Model, size: str) -> b rc_file = log_file.with_suffix('.rc') rc_file.write_text(str(job.returncode)) - if job.returncode == 0: - logger.info('Finished: {} -> {}', starting_surface, output_surf) - return True + if job.returncode != 0: + logger.error('FAILED -- check log file for details: {}', log_file) + return False + + thickness_commands_worked = True + for f in thickness_fwhm: + output_file = output_surf.with_suffix(f'.tlink_{f}mm.txt') + log_file = output_file.with_suffix('.log') + cmd = ['cortical_thickness', '-tlink', '-fwhm', str(f), output_surf, starting_surface, output_file] + with log_file.open('wb') as log_handle: + proc = sp.run(cmd, stdout=log_handle, stderr=log_handle) + if proc.returncode != 0: + logger.error('Command failed: {}', shlex.join(map(str, cmd))) + thickness_commands_worked = False - logger.error('FAILED -- check log file for details: {}', log_file) - return False + logger.info('Finished: {} -> {}', starting_surface, output_surf) + return thickness_commands_worked def locate_surface_for(mask: Path) -> Optional[Path]: @@ -116,5 +132,13 @@ def get_builtin_model(name: str) -> str: return str(model_file) +def __parse_thickness_fwhm(value) -> Sequence[int]: + try: + return [int(x) for x in value.split(',')] + except ValueError: + logger.error(f'"{value}" is not a comma-separated list of numbers') + sys.exit(1) + + if __name__ == '__main__': main()