|
| 1 | +""" |
| 2 | +The workflow builder factory method. |
| 3 | +
|
| 4 | +All the checks and the construction of the workflow are done |
| 5 | +inside this function that has pickleable inputs and output |
| 6 | +dictionary (``retval``) to allow isolation using a |
| 7 | +``multiprocessing.Process`` that allows dmriprep to enforce |
| 8 | +a hard-limited memory-scope. |
| 9 | +
|
| 10 | +""" |
| 11 | + |
| 12 | + |
| 13 | +def build_workflow(config_file, retval): |
| 14 | + """Create the Nipype Workflow that supports the whole execution graph.""" |
| 15 | + from niworkflows.utils.bids import collect_participants, check_pipeline_version |
| 16 | + from niworkflows.reports import generate_reports |
| 17 | + from .. import config |
| 18 | + from ..utils.misc import check_deps |
| 19 | + from ..workflows.base import init_dmriprep_wf |
| 20 | + |
| 21 | + config.load(config_file) |
| 22 | + build_log = config.loggers.workflow |
| 23 | + |
| 24 | + output_dir = config.execution.output_dir |
| 25 | + version = config.environment.version |
| 26 | + |
| 27 | + retval['return_code'] = 1 |
| 28 | + retval['workflow'] = None |
| 29 | + |
| 30 | + # warn if older results exist: check for dataset_description.json in output folder |
| 31 | + msg = check_pipeline_version( |
| 32 | + version, output_dir / 'dmriprep' / 'dataset_description.json' |
| 33 | + ) |
| 34 | + if msg is not None: |
| 35 | + build_log.warning(msg) |
| 36 | + |
| 37 | + # Please note this is the input folder's dataset_description.json |
| 38 | + dset_desc_path = config.execution.bids_dir / 'dataset_description.json' |
| 39 | + if dset_desc_path.exists(): |
| 40 | + from hashlib import sha256 |
| 41 | + desc_content = dset_desc_path.read_bytes() |
| 42 | + config.execution.bids_description_hash = sha256(desc_content).hexdigest() |
| 43 | + |
| 44 | + # First check that bids_dir looks like a BIDS folder |
| 45 | + subject_list = collect_participants( |
| 46 | + config.execution.layout, |
| 47 | + participant_label=config.execution.participant_label |
| 48 | + ) |
| 49 | + |
| 50 | + # Called with reports only |
| 51 | + if config.execution.reports_only: |
| 52 | + from pkg_resources import resource_filename as pkgrf |
| 53 | + |
| 54 | + build_log.log(25, 'Running --reports-only on participants %s', ', '.join(subject_list)) |
| 55 | + retval['return_code'] = generate_reports( |
| 56 | + subject_list, |
| 57 | + config.execution.output_dir, |
| 58 | + config.execution.work_dir, |
| 59 | + config.execution.run_uuid, |
| 60 | + config=pkgrf('dmriprep', 'config/reports-spec.yml'), |
| 61 | + packagename='dmriprep') |
| 62 | + return retval |
| 63 | + |
| 64 | + # Build main workflow |
| 65 | + INIT_MSG = """ |
| 66 | + Running dMRIPREP version {version}: |
| 67 | + * BIDS dataset path: {bids_dir}. |
| 68 | + * Participant list: {subject_list}. |
| 69 | + * Run identifier: {uuid}. |
| 70 | + * Output spaces: {spaces}. |
| 71 | + """.format |
| 72 | + build_log.log(25, INIT_MSG( |
| 73 | + version=config.environment.version, |
| 74 | + bids_dir=config.execution.bids_dir, |
| 75 | + subject_list=subject_list, |
| 76 | + uuid=config.execution.run_uuid, |
| 77 | + spaces=config.execution.output_spaces) |
| 78 | + ) |
| 79 | + |
| 80 | + retval['workflow'] = init_dmriprep_wf() |
| 81 | + |
| 82 | + # Check workflow for missing commands |
| 83 | + missing = check_deps(retval['workflow']) |
| 84 | + if missing: |
| 85 | + build_log.critical( |
| 86 | + "Cannot run dMRIPrep. Missing dependencies:%s", |
| 87 | + '\n\t* %s'.join(["{} (Interface: {})".format(cmd, iface) |
| 88 | + for iface, cmd in missing]) |
| 89 | + ) |
| 90 | + retval['return_code'] = 127 # 127 == command not found. |
| 91 | + return retval |
| 92 | + |
| 93 | + config.to_filename(config_file) |
| 94 | + build_log.info( |
| 95 | + "dMRIPrep workflow graph with %d nodes built successfully.", |
| 96 | + len(retval['workflow']._get_all_nodes()) |
| 97 | + ) |
| 98 | + retval['return_code'] = 0 |
| 99 | + return retval |
| 100 | + |
| 101 | + |
| 102 | +def build_boilerplate(config_file, workflow): |
| 103 | + """Write boilerplate in an isolated process.""" |
| 104 | + from .. import config |
| 105 | + |
| 106 | + config.load(config_file) |
| 107 | + logs_path = config.execution.output_dir / 'dmriprep' / 'logs' |
| 108 | + boilerplate = workflow.visit_desc() |
| 109 | + citation_files = { |
| 110 | + ext: logs_path / ('CITATION.%s' % ext) |
| 111 | + for ext in ('bib', 'tex', 'md', 'html') |
| 112 | + } |
| 113 | + |
| 114 | + if boilerplate: |
| 115 | + # To please git-annex users and also to guarantee consistency |
| 116 | + # among different renderings of the same file, first remove any |
| 117 | + # existing one |
| 118 | + for citation_file in citation_files.values(): |
| 119 | + try: |
| 120 | + citation_file.unlink() |
| 121 | + except FileNotFoundError: |
| 122 | + pass |
| 123 | + |
| 124 | + citation_files['md'].write_text(boilerplate) |
| 125 | + |
| 126 | + if not config.execution.md_only_boilerplate and citation_files['md'].exists(): |
| 127 | + from subprocess import check_call, CalledProcessError, TimeoutExpired |
| 128 | + from pkg_resources import resource_filename as pkgrf |
| 129 | + from shutil import copyfile |
| 130 | + # Generate HTML file resolving citations |
| 131 | + cmd = ['pandoc', '-s', '--bibliography', |
| 132 | + pkgrf('dmriprep', 'data/boilerplate.bib'), |
| 133 | + '--filter', 'pandoc-citeproc', |
| 134 | + '--metadata', 'pagetitle="dMRIPrep citation boilerplate"', |
| 135 | + str(citation_files['md']), |
| 136 | + '-o', str(citation_files['html'])] |
| 137 | + |
| 138 | + config.loggers.cli.info( |
| 139 | + 'Generating an HTML version of the citation boilerplate...') |
| 140 | + try: |
| 141 | + check_call(cmd, timeout=10) |
| 142 | + except (FileNotFoundError, CalledProcessError, TimeoutExpired): |
| 143 | + config.loggers.cli.warning( |
| 144 | + 'Could not generate CITATION.html file:\n%s', ' '.join(cmd)) |
| 145 | + |
| 146 | + # Generate LaTex file resolving citations |
| 147 | + cmd = ['pandoc', '-s', '--bibliography', |
| 148 | + pkgrf('dmriprep', 'data/boilerplate.bib'), |
| 149 | + '--natbib', str(citation_files['md']), |
| 150 | + '-o', str(citation_files['tex'])] |
| 151 | + config.loggers.cli.info( |
| 152 | + 'Generating a LaTeX version of the citation boilerplate...') |
| 153 | + try: |
| 154 | + check_call(cmd, timeout=10) |
| 155 | + except (FileNotFoundError, CalledProcessError, TimeoutExpired): |
| 156 | + config.loggers.cli.warning( |
| 157 | + 'Could not generate CITATION.tex file:\n%s', ' '.join(cmd)) |
| 158 | + else: |
| 159 | + copyfile(pkgrf('dmriprep', 'data/boilerplate.bib'), |
| 160 | + citation_files['bib']) |
0 commit comments