This is an old revision of the document!
Table of Contents
Pipeline de Procesamiento de FACE v0.5
Nueva version en etapa de planificacion.
Porque una nueva version?
- Introducir containers. Preparar el pipeline para utilizarlo en Microsoft Azure, AWS o similar. Todas las llamadas a FSL, Freesurfer o ANTs deben sustituirse por una llamada a containers. Nota: De momento no parece ser necesario y los containers de FSL o Fs pueden ser mas complicados de lo que parecen
Modularizacion de las llamadas a SLURM. Los script sbatch han de crearse y lanzarse a traves del modulo SLURM.pm. Deben reescribirse los scripts.DONE (Modulos del pipeline)- Reparalelizar los procesos de registro, y extraccion de metricas PET en modulos mas pequeños
Integracion del proyecto en githubDONE (https://github.com/asqwerty666/acenip)Revisar y escribir documentacion que falta. Las ayudas estan casi vacias, Hay que retorceder un paso y escribir lo que hace cada script para evitar la duplicacion de esfuerzo.DONEMejorar la integracion con XNAT. Integrar el QC de Freesurfer a XNAT y al pipeline en lugar de ejecutar procesos de matlab.DONE (QC de Freesurfer con VisualQC CLI, Realizar el QC a la segmentacion de Freesurfer de los sujetos analizados en XNAT)Usar Freesurfer 7.2 Release NotesDONE (Update Freesurfer 7.2)
TODO
Dependencias
- dcm2bids: https://pypi.org/project/dcm2bids/
- Freesurfer: https://surfer.nmr.mgh.harvard.edu/
- fmriprep: https://fmriprep.org/en/stable/
- dicom3tools: https://www.dclunie.com/dicom3tools.html (no estrictamente necesario pero conveniente)
- xnatapic: https://github.com/asqwerty666/xnatapic (para las operaciones con XNAT)
DB
Aunque las operaciones simples como la segmentacion Freesurfer y el calculo de centiloide para PET-FBB se han desplazadoa XNAT, para otras operaciones es necesario crear la DB del proyecto de la misma manera que en la version anterior.
El primer punto a considerar es la separacion correcta entre el software y los datos. Cada proyecto se caracteriza por,
- NAME: El nombre del proyecto
- SRC_PATH: La ruta donde se encuentran los archivos fuentes del proyecto (DICOMs)
- PROJ_PATH: La ruta donde se ejecuta el procesamiento, se guardan archivos intemedios y resultados.
Cada sujeto se caracteriza por,
- PID: identificador dentro del proyecto. Enlaza todos los datos del sujeto entre si.
- NID: identificador dentro del procesamiento de neuroimagen. Identifica los datos de cada sujeto dentro del proyecto.
- SUB_PATH: Identifica la ubicacion de los datos (DICOMs) dentro del proyecto. Puede ser mas de uno. MRI_PATH, PET_PATH. Si hay mas de una fecha (longitudinal) tambien debe distinguirse.
Teniendo esto en cuenta podemos abstraer dos procedimientos,
- make_proj.pl → creacion del proyecto
- update_mri_db.pl → creacion y actualizacion de la DB del proyecto.
- update_pet_db.pl → actualizacion de la DB del proyecto para PET.
Bien organizado, la creacion del proyecto queda reducida a un script simple,
El manejo de la base de datos es algo mas complicado pero no demasiado
y para ejecutarlo se hace algo como,
[tester@detritus ~]$ mkdir /nas/data/ptest [tester@detritus ~]$ mkdir -p ~/.config/neuro [tester@detritus ~]$ make_proj.pl ptest /nas/tester/testproj [tester@detritus ~]$ tree /nas/data/ptest/ /nas/data/ptest/ ├── bids └── working 2 directories, 0 files [tester@detritus ~]$ cat ~/.config/neuro/ptest.cfg DATA = /nas/data/ptest SRC = /nas/tester/testproj WORKING = /nas/data/ptest/working BIDS = /nas/data/ptest/bids [tester@detritus ~]$ update_mri_db.pl ptest [tester@detritus ~]$ cat /nas/data/ptest/ids.csv 032-00001-SCR-GLOBAL,1 032-00002-SCR-GLOBAL,2 032-00003-SCR,3 032-00004-SCR,4 032-00005-SCR-GLOBAL,5 032-00007-SCR-GLOBAL,6 032-00008-SCR,7 032-00009,8 [tester@detritus ~]$ cat /nas/data/ptest/ptest_mri.csv 0001;032-00001-SCR-GLOBAL 0002;032-00002-SCR-GLOBAL 0003;032-00003-SCR 0004;032-00004-SCR 0005;032-00005-SCR-GLOBAL 0006;032-00007-SCR-GLOBAL 0007;032-00008-SCR 0008;032-00009
DCM2BIDS
El proceso de conversion de los DICOM a formato BIDS ha de hacerse manualmente. Esto es, aunque con ayuda de herramientas (Convertir DICOMs a BIDS), la conversion necesita que se realicen ciertos pasos no automatizados. Dado la disimilitud de los proyectos, los archivos han de editarse y el proceso de conversion de al menos uno de los sujetos ha de revisarse para automatizar el resto.
El primer paso para la conversión ha de ser ejecutar dcm2bids_scaffold dentro del directorio bids del proyecto. Esto crea la estructura necesaria para la ejecucion.
[tester@detritus bids]$ dcm2bids_scaffold [tester@detritus bids]$ ls CHANGES code dataset_description.json derivatives participants.json participants.tsv README sourcedata
El archivo dataset_description.json ha de editarse manualmente, pero es bastante sencillo,
[tester@detritus bids]$ cat dataset_description.json { "Name": "PTEST", "BIDSVersion": "1.2.0", "License": "CC0" }
Ahora debemos escoger un sujeto del proyecto para examinar la estructura de los datos,
[tester@detritus bids]$ dcm2bids_helper -d /nas/tester/testproj/032-00001-SCR-GLOBAL/ Example in: /nas/data/ptest/bids/tmp_dcm2bids/helper
La estructura dejada por este comando, junto al protocolo de maquina permite llenar el archivo de configuracion necesario para la conversion de los sujetos. Esto ha de hacerse con cuidado, pero una vez rellenado correctamente la conversion es sencilla.
Ejemplo basado en el protocolo de EPAD
En este punto ya podemos ejecutar la conversion de cualquier sujeto usando dcm2bids,
$ dcm2bids -d /src_path/ -p subj_id -c config_file.json -o proj_path/bids/
Lo que es deseable es ejecutar la conversion de todos los sujetos del proyecto usando el cluster. ahora bien,una vez que el archivo de configuracion se ha editado correctamente ya se puede utilizar una herramienta generica.
Lo programamos entonces en el pipeline
[tester@detritus ptest]$ bulk2bids.pl ptest [tester@detritus ptest]$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 114181 devel fs_recon tester PD 0:00 1 (Dependency) 114191 devel dcm2bids tester PD 0:00 1 (Dependency) 114184 devel dcm2bids tester R 0:42 1 brick01 114185 devel dcm2bids tester R 0:42 1 brick01 114186 devel dcm2bids tester R 0:42 1 brick01 114187 devel dcm2bids tester R 0:42 1 brick01 114188 devel dcm2bids tester R 0:42 1 brick01 114189 devel dcm2bids tester R 0:42 1 brick01 [tester@detritus ptest]$ tail -f slurm/dcm2bids0002-114184 INFO:dcm2bids.dcm2bids:--- dcm2bids start --- INFO:dcm2bids.dcm2bids:OS:version: Linux-3.10.0-862.11.6.el7.x86_64-x86_64-with-centos-7.5.1804-Core INFO:dcm2bids.dcm2bids:python:version: 3.6.8 (default, Aug 7 2019, 17:28:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] INFO:dcm2bids.dcm2bids:dcm2bids:version: 2.1.4 INFO:dcm2bids.dcm2bids:dcm2niix:version: v1.0.20191031 INFO:dcm2bids.dcm2bids:participant: sub-0002 INFO:dcm2bids.dcm2bids:session: INFO:dcm2bids.dcm2bids:config: /home/data/ptest/bids/conversion.json INFO:dcm2bids.dcm2bids:BIDS directory: /home/data/ptest/bids INFO:dcm2bids.utils:Running dcm2niix -b y -ba y -z y -f '%3s_%f_%p_%t' -o /nas/data/ptest/bids/tmp_dcm2bids/sub-0002 /nas/tester/testproj/032-00002-SCR-GLOBAL/ .........
Issues
A veces dmc2niix falla y se interrumpe la ejecucion de dcm2bids. Workaround: Separar los procesos de dcm2niix y dcm2bids. Primero convierto y despues organizo.De paso tengo mas control sobre como convierto (Ver respuesta de Chris Rorden)
my $order = "mkdir -p $std{'DATA'}/bids/tmp_dcm2bids/sub-$subject; dcm2niix -i y -b y -ba y -z y -f '%3s_%f_%p_%t' -o $std{'DATA'}/bids/tmp_dcm2bids/sub-$subject $std{'SRC'}/$guys{$subject}/; dcm2bids -d $std{'SRC'}/$guys{$subject}/ -p $subject -c $std{'DATA'}/$cfile -o $std{'DATA'}/bids/";
Segmentación Freesurfer
En esta nueva version la segmentacio de Freesurfer ya no se lanza manualmente en el pipeline sino que se realiza en XNAT. Esto tiene algunas ventajas,
- Se hace automaticamente - No hay que ir buscando los sujetos que faltan por lanzar - Se puede repetir un proceso pero nunca hay que hacerlo, los datos estan en la DB, solo hay que bajarlos cuando se requiera
Entonces, la segmentacion de Freesurfer se realiza automaticamente por medio del pipeline RunFreesurfer al subir las MRI. O se lanza mediante algo como,
$ xnatapic run_pipeline --project_id f5cehbi --pipeline RunFreesurfer --experiment_id XNAT5_E00752
Los resultados quedan almacenados en el servidor de XNAT.
Obtener estadisticas
Para obtener las estadisticas de un proceso utilizamos xnat_pullfs.pl.
Las opciones de input del script son,
- -s : indica que estadisticas queremos sacar (default: aseg)
- -p : nombre del proyecto, igual a -x, se mantiene por compatibilidad
- -x : nombre del proyecto
- -o : archivo de output (default: STDOUT)
Lo primero que hace el script es sacar los sujetos que estan definidos en XNAT,
$ xnatapic list_subjects --project_id f5cehbi --label > xnat_subjects.list
e intentar averiguar los ID de los experimentos para cada MRI correspondiente
$ for x in `awk -F"," {'print $1'} xnat_subjects.list`; do e=$(xnatapic list_experiments --project_id f5cehbi --subject_id ${x} --modality MRI); if [[ ${e} ]]; then echo "${x},${e}"; fi; done > xnat_subject_mri.list
Ahora hago un join de xnat_subjects.list y xnat_subject_mri.list y este es el archivo base segun el cual interrogare a XNAT y guardare los resultados.
Ahora, para cada experimento de XNAT debo pedir el archivo de estadisticas que deseo, y guardarlas por separado para cada sujeto.
$ xnatapic get_fsresults --experiment_id ${var_experimento} --stats ${var_stats} ${tmp_subject_dir}
Ya solo tengo que parsear el archivo para sacar los datos que me interesan. Esto no es complicado y lo he hecho con greps directamente pero el formato cambia entre archivos por lo que hay que parsear distinto cada vez. A lo mejor no lo mas eficiente pero si lo mas sencillo, es añadir los trozos en dependencia de que estadisticas se pidan. ( quizas lo suyo seria meter cada parser en subrutinas?)
De momento se pueden bajar la segmentacion subcortical (aseg.stats) y la parcelacion cortical (aparc.stats), no obstante el proceso para bajar otras stats no deberia diferir mucho y puede irse añadiendo a demanda, ya que tenemos estas de plantilla.
Obtener directorio completo de FS
Para hacer esto debemos tener creado el proyecto local con la configuracion definida en $HOME/.config/neuro y un archivo project_mri.csv definiendo los ID y label de los sujetos. Ejemplo,
[osotolongo@brick03 f5cehbi]$ head f5cehbi_mri.csv 0001;F001 0002;F005 0003;F006 0004;F007 0005;F009 0006;F010 0007;F014 0008;F015 0009;F023 0010;F024
A veces quereoms hacer procedimientos que dependen de tener la segmentacion de FS. Para ello podemos utlizar el script xnat_getfs.pl
Despues de tener enlazados el sujeto local con el experiemento local, se trata de bajar todo el directorio de procesamiento de FS y descomprimirlo a un directorio local. El directorio local debe ser el que se espera que exista si ha ejecutado el pipeline de FS localmente.
Deberia ser algo como: ${SUBJECTS_DIR}/${project_name}_${img_ID}/
.
Asi que hay que hacer,
$ xnatapic get_fsresults --experiment_id ${var_experimento} --all-tgz ${tmp_subject_dir} $ tar xzvf ${tmp_subject_dir}/*.tgz -C ${SUBJECTS_DIR}/${project_name}_${img_ID}/ --transform='s/${XNAT_subject_ID}//' --exclude=fsaverage
y quedan todos los archivos de FS en su lugar.
Para poner un ejemplo concreto, si miramos los datos del sujeto F014 en el proyecto local f5cehbi,
[osotolongo@brick03 f5cehbi]$ grep F014 f5cehbi_mri.csv 0007;F014
al ejecutar el script nos quedarian los datos de la segmentacion del experimento XNAT_E00110 en el directorio /nas/data/subjects/f5cehbi_0007/ .
[osotolongo@brick03 f5cehbi]$ ls /nas/data/subjects/f5cehbi_0007/ label mri scripts stats surf tmp touch trash
Bajar proyecto de XNAT
Una a vez procesada la segmentación de Freesurfer, si queremos hacer algo mas complejo, hemos de bajar ordenadamente el directorio de procesamiento de cada sujeto. El primer paso sería crear el proyecto local, pero no es necesario (al menos en principio) identificar la posicion de las imagenes RAW. Es decir que practicamente se puede hacer a mano a partir del listado de XNAT.
Asi que voy a hacer un config falso,
[osotolongo@brick03 mri_face]$ mkdir raw [osotolongo@brick03 mri_face]$ pwd /old_nas/mri_face [osotolongo@brick03 mri_face]$ make_proj.pl mriface /old_nas/mri_face/raw [osotolongo@brick03 mri_face]$ cat ~/.config/neuro/mriface.cfg DATA = /nas/data/mriface SRC = /old_nas/mri_face/raw WORKING = /nas/data/mriface/working BIDS = /nas/data/mriface/bids
y esto lo edito como quiera,
[osotolongo@brick03 mri_face]$ vim ~/.config/neuro/mriface.cfg [osotolongo@brick03 mri_face]$ mkdir bids [osotolongo@brick03 mri_face]$ mkdir working [osotolongo@brick03 mri_face]$ cat ~/.config/neuro/mriface.cfg DATA = /old_nas/mriface SRC = /old_nas/mri_face/raw WORKING = /old_nas/mriface/working BIDS = /old_nas/mriface/bids
El listado de sujetos se baja de XNAT,
[osotolongo@brick03 mri_face]$ head osotolongo_1_10_2022_10_19_42.csv Subject,MR Sessions 20081210,1 20140947,1 20151338,1 20160418,1 20191274,1 20200484,1 20201297,1 2021020098,1 20210716,1
La DB debería ser facil de construir,
[osotolongo@brick03 mri_face]$ n=1; for x in $(awk -F"," '{if ($1 ~ /^[0-9]/) print $1}' osotolongo_1_10_2022_10_19_42.csv); do printf "%04d;%s\n" "${n}" "${x}"; n=$((n+1)); done > mriface_mri.csv [osotolongo@brick03 mri_face]$ head mriface_mri.csv 0001;20081210 0002;20140947 0003;20151338 0004;20160418 0005;20191274 0006;20200484 0007;20201297 0008;2021020098 0009;20210716 0010;20210955
https://github.com/asqwerty666/acenip/blob/main/bin/xnat_getfs.pl
Hippocampal Subfields
A esta version se le ha añadido la capacidad de extraer la segmentacion del hipocampo y la amigadala
Preprocesamiento SBM
pqcache.pl
Freesurfer QC
DTI preproc
El procesamiento no cambia mucho del que se realiza en la version anterior. No obstante, al tomar los archivos del formato BIDS, la estructura en que se guarda es por completo abstracta del software y la comprobaicon de los archivos (y posterior toma de decisiones) se puede individualizar en una subrutina externa.
Nota: deben existirlos archivos acqparams.txt y dti_index.txt. Ver como hacer el index.txt y el acqparams.txt
El registro es ahora un poco mas sencillo
Los procedimientos individuales de registro si han de cambiarse poco, mas que nada el input, lo demas es estrictamente igual
[tester@detritus ptest]$ dti_reg.pl ptest [tester@detritus ptest]$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 114225 cuda dti_reg_ tester PD 0:00 1 (Resources) 114226 cuda dti_reg_ tester PD 0:00 1 (Priority) 114227 cuda dti_reg_ tester PD 0:00 1 (Priority) 114228 cuda dti_reg_ tester PD 0:00 1 (Priority) 114229 cuda dti_reg_ tester PD 0:00 1 (Priority) 114230 cuda dti_reg_ tester PD 0:00 1 (Priority) 114231 devel dti_reg_ tester PD 0:00 1 (Dependency) 114223 cuda dti_reg_ tester R 0:05 1 brick01 114224 cuda dti_reg_ tester R 0:05 1 brick01 [tester@detritus ptest]$ ls working/0001_* working/0001_brain.nii.gz working/0001_dti_L1.nii.gz working/0001_dti_MO.nii.gz working/0001_dti_V3.nii.gz working/0001_mni_to_b0.nii.gz working/0001_dti_brain_mask.nii.gz working/0001_dti_L2.nii.gz working/0001_dti_S0.nii.gz working/0001_hifi_b0.nii.gz working/0001_t1_b0.nii.gz working/0001_dti_data.nii.gz working/0001_dti_L3.nii.gz working/0001_dti_V1.nii.gz working/0001_JHU_labels.nii.gz working/0001_t1_reoriented.nii.gz working/0001_dti_FA.nii.gz working/0001_dti_MD.nii.gz working/0001_dti_V2.nii.gz working/0001_JHU_tracts.nii.gz
Probando el -cut (que esta reescrito completo),
[tester@detritus ptest]$ cat repdti.txt 0004 [tester@detritus ptest]$ dti_reg.pl -cut repdti.txt ptest [tester@detritus ptest]$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 114233 devel dti_reg_ tester PD 0:00 1 (Dependency) 114232 cuda dti_reg_ tester R 6:25:12 1 brick01
DTI registro, QC
DTI metrics (Atlas)
[tester@detritus ptest]$ dti_metrics.pl -a1 ptest [tester@detritus ptest]$ dti_metrics.pl -a2 ptest [tester@detritus ptest]$ ls ptest_dti_* ptest_dti_labels.csv ptest_dti_labels_results.tgz ptest_dti_tracts.csv ptest_dti_tracts_results.tgz
TRACULA
La implementacion de Tracula en FS7.2 ha cambiado para pemitir la correcion por topup. Asi que hay que hacer un dmri.rc distinto. Entonces, ahora hay que correr 7 scripts,
- ctrac_dmri.pl –> Crear el dmri.rc
- ctrac_prep.pl –> Preprocesamiento DTI
- ctrac_bedp.pl –> bedtrack
- ctrac_path.pl –> probtrack
- ctrac_stat.pl –> Estadisticas globales
- ctrac_metrics.pl –> Metricas medias de los principales tractos
- ctrac_report.pl –> QC report
DTI metrics VOIs
Las metricas de DTI pueden exrtaerse en cualquiera de los tractos definidos, ya sea mediante atlas o a traves de TRACULA. Lo que ocurre es que en la realidad estos tractos son demasiado específicos. Es decir, no nos interesa la FA en el Genu of corpus callosum sino mas bien en el Corpus callosum en su totalidad. Hay dos enfoques validos para conseguir esto ultimo.
ICBM VOIs
Para calcular una mascara de los tractos completos (VOI) basta con tomar las mascaras de los trozos individuales y sumarlos todos juntos en una mscara binaria. Esta mascara es la que luego se aplicara a la imagen FA y se calculara el valor medio dentro.
Para esto necesitamos saber que trozos componen cada VOI. Esto lo voy a almacenar en un archivo de texto ya que no cambiara nunca. Ejemplo, para el atlas ICBM-DTI-81,
Corpus_callosum:3,4,5 Internal_capsule:17,18,19,20,21,22 Corona_radiata:23,24,25,26,27,28 Superior_longitudinal_fasciculus:41,42 Fornix:6,39,40 Cingulum:35,36,37,38 Uncinate_fasciculus:45,46
Este archivo lo he de leer y tomar cada archivo XXXX_JHU_labels individual y calcular ahi la porcion con la que he de fabricar la mascara. Luego se suman y se saca el valor deseado.
foreach my $subject (@dtis){ my $dti_fa = $w_dir.'/'.$subject.'_dti_FA.nii.gz'; my $dti_md = $w_dir.'/'.$subject.'_dti_MD.nii.gz'; if($subject && -e $dti_fa){ foreach my $rmask (sort keys %masks){ my @chunks = split /,/,$masks{$rmask}; my @orarg; foreach my $chunk (@chunks){ my $order = "fslmaths ".$w_dir."/".$subject."_JHU_".$lort{$atlas}." -uthr ".$chunk." -thr ".$chunk." -div ".$chunk." ".$w_dir."/.tmp_".$subject."/JHU_".$chunk."_tmp"; print "$order\n"; system($order); my $tmpstr = $w_dir."/.tmp_".$subject."/JHU_".$chunk."_tmp"; push @orarg, $tmpstr; } my $strarg = join " -add ", @orarg; my $order = "fslmaths ".$strarg." ".$w_dir."/.tmp_".$subject."/JHU_".$rmask."_tmp"; print "$order\n"; system($order); } print OF "$subject"; foreach my $rmask (sort keys %masks){ my $order = "fslstats ".$dti_fa." -k ".$w_dir."/.tmp_".$subject."/JHU_".$rmask."_tmp -M -S"; print "$order\n"; (my $mean, my $std) = map{/(\d+\.\d*)\s*(\d+\.\d*)/} qx/$order/; if($with_sd){ print OF ";$mean",";$std"; }else{ print OF ";$mean"; } $order = "fslstats ".$dti_md." -k ".$w_dir."/.tmp_".$subject."/JHU_".$rmask."_tmp -M -S"; print "$order\n"; ($mean, $std) = map{/(\d+\.\d*)\s*(\d+\.\d*)/} qx/$order/; if($with_sd){ print OF ";$mean",";$std"; }else{ print OF ";$mean"; } } print OF "\n"; } } close OF;
El codigo completo puede encontrarse en github y
para ejecutarlo basta con hacer,
$ dti_metrics_comp.pl project
o,
$ dti_metrics_comp.pl -a1 project
para hacerlo con el atlas JHU-WM-tractography (on development).
En el primer caso los resultados quedarian en el archivo bioface_dti_icbm_comp.csv,
[osotolongo@brick03 bioface]$ head bioface_dti_icbm_comp.csv Subject;Cingulum_FA;Cingulum_MD;Corona_radiata_FA;Corona_radiata_MD;Corpus_callosum_FA;Corpus_callosum_MD;Fornix_FA;Fornix_MD;Internal_capsule_FA;Internal_capsule_MD;Superior_longitudinal_fasciculus_FA;Superior_longitudinal_fasciculus_MD;Uncinate_fasciculus_FA;Uncinate_fasciculus_MD 0002;0.477487;0.000786;0.433740;0.000744;0.647378;0.000841;0.554593;0.000944;0.556976;0.000720;0.474224;0.000726;0.566348;0.000788 0003;0.494214;0.000800;0.439710;0.000787;0.616569;0.000850;0.577302;0.000925;0.560079;0.000730;0.425376;0.000787;0.431516;0.000902 0004;0.416937;0.000813;0.398660;0.000779;0.595173;0.000903;0.490137;0.001118;0.559346;0.000735;0.410975;0.000748;0.468427;0.000809 0005;0.427343;0.000794;0.404245;0.000765;0.591447;0.000888;0.460360;0.001119;0.563446;0.000757;0.426342;0.000773;0.510532;0.000755 0006;0.475403;0.000801;0.431013;0.000781;0.596390;0.000889;0.521160;0.001085;0.560720;0.000742;0.474176;0.000756;0.471718;0.000817 0007;0.474952;0.000768;0.460331;0.000757;0.575729;0.000977;0.407189;0.001516;0.581289;0.000731;0.465529;0.000735;0.521556;0.000757 0008;0.437555;0.000801;0.416142;0.000778;0.596577;0.000866;0.497081;0.001035;0.554840;0.000767;0.426218;0.000771;0.518556;0.000786 0009;0.442004;0.000812;0.431805;0.000747;0.630885;0.000814;0.499554;0.001055;0.539465;0.000748;0.470043;0.000736;0.537202;0.000756 0010;0.473434;0.000748;0.447876;0.000740;0.626619;0.000852;0.511838;0.001002;0.601466;0.000712;0.470705;0.000716;0.529629;0.000725
TRACULA VOIs
Los valores de FA y MD de los tractos completos tambien puede derivarse de TRACULA. En este caso no reconstruiremos el tracto como tal sino que tomaremos los valores de FA individuales y asumiremos que,
$$ {FA}_{VOI} \approx \frac{\sum{{FA}_{i}*V_{i}}}{\sum{V_{i}}} $$
donde ${FA}_{i}$ son los valores de FA y $V_{i}$ el volumen, de los tractos individuales, respectivamente.
Asi que primero tengo que tener almacenado en un fichero que variables forman cada VOI,
Fornix:lh.fx,rh.fx Cingulum:lh.cbd,lh.cbv,rh.cbd,rh.cbv Uncinate_fasciculus:lh.uf,rh.uf Superior_longitudinal_fasciculus:lh.slf1,lh.slf2,lh.slf3,rh.slf1,rh.slf2,rh.slf3 Inferior_longitudinal_fasciculus:lh.ilf,rh.ilf Corpus_callosum:cc.bodyc,cc.bodyp,cc.bodypf,cc.bodypm,cc.bodyt,cc.genu,cc.rostrum,cc.splenium
y esto lo leo directamente de los resultados de tracula para cada individuo. Podria leerlo de los achivos de FS pero lo que voy a hacer es,
- Cambiar el script de metricas de TRACULA para incluir el volumen de los tractos
- Asumir que he ejecutado las metrcas de TRACULA y leer directamente este archivo para calcular los resultados (mucho mas rapido)
El resultado de esto es el script en github que se ejecuta como,
[osotolongo@brick03 bioface]$ ctrac_translate.pl bioface
y deja los resultados en bioface_dti_tracula_composed.csv,
Subject,Cingulum_FA,Cingulum_MD,Corpus_callosum_FA,Corpus_callosum_MD,Fornix_FA,Fornix_MD,Inferior_longitudinal_fasciculus_FA,Inferior_longitudinal_fasciculus_MD,Superior_longitudinal_fasciculus_FA,Superior_longitudinal_fasciculus_MD,Uncinate_fasciculus_FA,Uncinate_fasciculus_MD 0001,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 0002,0.500092918105356,0.000781457339530766,0.519852793601731,0.000781114487752106,0.466710179411765,0.00105999035294118,0.504764250681199,0.000813264,0.436700603806417,0.000742181515280044,0.468751002475248,0.000772750495874587 0003,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 0004,0.471647589821662,0.000811000234449761,0.512361431638802,0.00081236424127981,0.386831987261146,0.000992012576433121,0.452685824742268,0.000871269313402062,0.417407322635963,0.00077327638510534,0.419668255865922,0.000848094241340782 0005,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 0006,0.486058795640327,0.000798137305177112,0.52619407984211,0.000808463441643492,0.449970944306931,0.000960078674504951,0.496323946902655,0.000859897426548673,0.44573164370485,0.000777395058565531,0.463258846660395,0.000819830761994355 0007,0.476584601431981,0.000773005742243437,0.525463044190302,0.000778800766056725,0.308487,0.00163514,0.517803210059172,0.000801609260946746,0.451237894539822,0.00074905124422357,0.467696353195164,0.000769760035405872 0008,0.470472873369794,0.000793977488851493,0.501802720765106,0.000807642284451529,0.433634495232041,0.00100513844373808,0.461641992471769,0.000858071812630698,0.402474214795654,0.000775522433212623,0.442492631840796,0.00079464460199005 0009,0.513032479578393,0.000781708291172596,0.524635845259849,0.000773339304509904,0.437998623059867,0.00105553261640798,0.479583220908231,0.000831665455061495,0.447428453367876,0.00074106617074894,0.461369545135846,0.00078089697283085
Comparando ICBM vs TRACULA
DTI Tractography
La tractografia puede hacerse utilizando regiones definidas en la reconstruccion de FS o un atlas externo. En este caso el atlas externo escogido es el de la UofM.
Voy a simplificar un poco el procesamiento anterior porque hay muchas cosas que no se usan. En caso de necesitarlas ya se volveran a implementar.
Primero el bedpostx y el probtrackx.
- Los dos modos de procesamiento que hay implementados tienen identico resultado. Basta con dejar uno (el mas rapido o sencillo) y nos quitamos una variable de encima.
- Pasamos el registro de ANTS a la nueva sintaxis, ya que hemos cambiado el registro y las matrices son otras
Vamos a probar uno,
[tester@brick01 ptest]$ cat dti_track.seed 10 49 [tester@brick01 ptest]$ dti_bedtrack_cuda.sh ptest 0001 /nas/data/ptest/working Copying files Making bedpostx [Tue Dec 10 10:36:45 CET 2019] --------------------------------------------- ------------ BedpostX GPU Version ----------- --------------------------------------------- subjectdir is /nas/data/ptest/working/.tmp_0001/bedpostx Making bedpostx directory structure Copying files to bedpost directory Pre-processing stage Queuing parallel processing stage ----- Bedpostx Monitor ----- 1 parts processed out of 4 2 parts processed out of 4 3 parts processed out of 4 ..... ..... ..... Done loading samples. Volume seeds volume 1 volume 2 time spent tracking: 1708 seconds save results finished Done [Tue Dec 10 11:39:22 CET 2019] [tester@brick01 ptest]$ ls /nas/data/ptest/working/0001_probtrack_out/ fdt_paths.nii.gz probtrackx.log waytotal
Esto es eterno, asi que paciencia.
Ahora con el UofM,
[tester@brick01 ptest]$ dti_bedtrack_nodes.sh ptest 0001 /nas/data/ptest/working/ /nas/software/neuro_4_0/lib/uofm/Nodes/LN/ Copying files Making bedpostx [Tue Dec 10 15:53:58 CET 2019] --------------------------------------------- ------------ BedpostX GPU Version ----------- --------------------------------------------- subjectdir is /nas/data/ptest/working/.tmp_0001/bedpostx /nas/data/ptest/working/.tmp_0001/bedpostx has already been processed: /nas/data/ptest/working/.tmp_0001/bedpostx.bedpostX. Delete or rename /nas/data/ptest/working/.tmp_0001/bedpostx.bedpostX before repeating the process. So far, so good [Tue Dec 10 15:53:58 CET 2019] Getting nodes and making masks ..... ..... ..... Done loading samples. Volume seeds volume 1 volume 2 volume 3 volume 4 volume 5 volume 6 volume 7 time spent tracking: 3714 seconds save results finished Done [Tue Dec 10 17:03:25 CET 2019] [tester@brick01 ptest]$ ls /nas/data/ptest/working/0001_probtrack_out/ fdt_paths.nii.gz probtrackx.log waytotal
Nota: Ya tengo el bedpostx hecho asi que demorara menos, pero igual son varios nodos a registrar al DTI.
Parece que todo funciona asi que nos vamos al wrapper,
[tester@detritus ptest]$ dti_track.pl ptest [tester@detritus ptest]$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 114236 cuda dti_trac tester PD 0:00 1 (Resources) 114237 cuda dti_trac tester PD 0:00 1 (Priority) 114238 cuda dti_trac tester PD 0:00 1 (Priority) 114239 cuda dti_trac tester PD 0:00 1 (Priority) 114240 cuda dti_trac tester PD 0:00 1 (Priority) 114241 devel dti_trac tester PD 0:00 1 (Dependency) 114234 cuda dti_trac tester R 0:03 1 brick01 114235 cuda dti_trac tester R 0:03 1 brick01
Importante: : Al terminar, mover los directorios al path correcto,ejemplo,
for x in `ls -d working/*_probtrack_out`; do mv $x `echo $x | sed 's/out/DMN/'`;done
ICA individual
El procedimiento para ICA de un sujeto fue descrito ampliamente usando el protocolo MOPEAD. Aqui hay que cambiar el input y alguna cosa mas,
Ahora a probarlo,
[tester@detritus ptest]$ rs_ica_one.pl ptest Collecting needed files sbatch /nas/data/ptest/working/0001_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114303 /nas/data/ptest/working/0001_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114304 /nas/data/ptest/working/0001_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0002_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114306 /nas/data/ptest/working/0002_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114307 /nas/data/ptest/working/0002_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0003_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114309 /nas/data/ptest/working/0003_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114310 /nas/data/ptest/working/0003_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0004_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114312 /nas/data/ptest/working/0004_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114313 /nas/data/ptest/working/0004_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0005_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114315 /nas/data/ptest/working/0005_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114316 /nas/data/ptest/working/0005_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0006_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114318 /nas/data/ptest/working/0006_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114319 /nas/data/ptest/working/0006_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0007_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114321 /nas/data/ptest/working/0007_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114322 /nas/data/ptest/working/0007_rs.ica/scripts/feat4.sh sbatch /nas/data/ptest/working/0008_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114324 /nas/data/ptest/working/0008_rs.ica/scripts/feat2.sh sbatch --depend=afterok:114325 /nas/data/ptest/working/0008_rs.ica/scripts/feat4.sh Submitted batch job 114327 [tester@detritus ptest]$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 114304 devel feat-pte tester PD 0:00 1 (Dependency) 114305 devel feat-pte tester PD 0:00 1 (Dependency) 114307 devel feat-pte tester PD 0:00 1 (Dependency) 114308 devel feat-pte tester PD 0:00 1 (Dependency) 114310 devel feat-pte tester PD 0:00 1 (Dependency) 114311 devel feat-pte tester PD 0:00 1 (Dependency) 114313 devel feat-pte tester PD 0:00 1 (Dependency) 114314 devel feat-pte tester PD 0:00 1 (Dependency) 114316 devel feat-pte tester PD 0:00 1 (Dependency) 114317 devel feat-pte tester PD 0:00 1 (Dependency) 114319 devel feat-pte tester PD 0:00 1 (Dependency) 114320 devel feat-pte tester PD 0:00 1 (Dependency) 114322 devel feat-pte tester PD 0:00 1 (Dependency) 114323 devel feat-pte tester PD 0:00 1 (Dependency) 114325 devel feat-pte tester PD 0:00 1 (Dependency) 114326 devel feat-pte tester PD 0:00 1 (Dependency) 114327 devel feat-pte tester PD 0:00 1 (Dependency) 114303 devel feat-pte tester R 0:16 1 brick01 114306 devel feat-pte tester R 0:13 1 brick01 114309 devel feat-pte tester R 0:13 1 brick01 114312 devel feat-pte tester R 0:10 1 brick01 114315 devel feat-pte tester R 0:07 1 brick01 114318 devel feat-pte tester R 0:07 1 brick01 114321 devel feat-pte tester R 0:04 1 brick01 114324 devel feat-pte tester R 0:01 1 brick01 [tester@detritus ptest]$ ls -d working/*rs.ica working/0001_rs.ica working/0002_rs.ica working/0003_rs.ica working/0004_rs.ica working/0005_rs.ica working/0006_rs.ica working/0007_rs.ica working/0008_rs.ica
so far so good
ICA grupal
Este procedimiento es mucho mas complicado pero por esa misma razon esta escrito mucho mas abstracto.
Asi que apenas hay que cambiar nada
[tester@detritus ptest]$ rs_ica_group.pl ptest Collecting needed files Counting available subjects Getting info from images Checking images and excluding wrong subjects Copying FSL files and setting directories Making global .fsf file Making individual .fsf files and scripts sbatch /nas/data/ptest/working/0001_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114328 /nas/data/ptest/working/0001_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0002_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114330 /nas/data/ptest/working/0002_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0003_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114332 /nas/data/ptest/working/0003_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0004_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114334 /nas/data/ptest/working/0004_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0005_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114336 /nas/data/ptest/working/0005_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0006_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114338 /nas/data/ptest/working/0006_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0007_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114340 /nas/data/ptest/working/0007_rs.ica/scripts/feat2.sh sbatch /nas/data/ptest/working/0008_rs.ica/scripts/feat1.sh sbatch --depend=afterok:114342 /nas/data/ptest/working/0008_rs.ica/scripts/feat2.sh Making global script sbatch --depend=afterok:114329,114331,114333,114335,114337,114339,114341,114343 /nas/data/ptest/working/rs.gica/scripts/feat4_ica.sh Submitted batch job 114344 [tester@detritus ptest]$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 114344 devel feat-pte tester PD 0:00 1 (Dependency) 114329 devel feat-pte tester R 0:05 1 brick02 114331 devel feat-pte tester R 0:11 1 brick01 114333 devel feat-pte tester R 0:11 1 brick01 114335 devel feat-pte tester R 0:05 1 brick01 114337 devel feat-pte tester R 0:05 1 brick02 114339 devel feat-pte tester R 0:05 1 brick01 114341 devel feat-pte tester R 0:05 1 brick02 114343 devel feat-pte tester R 0:05 1 brick01
PET-FBB DB
PET-FBB
El analisis PET-FBB tambien se ejecuta en XNAT pero en principio no automaticamente. Esto se puede cambiar en cualquier momento en el proyecto pero debido a la falta de sincronizacion entre la entrega de imagenes MRI y PET he preferido no hacerlo.
Ejecucion
Primero encontramos los experimentos correctos,
[osotolongo@brick03 facehbi]$ xnatapic list_experiments --project_id facehbi --type | grep petSessionData | awk -F"," {'print $1'} > xnat_pet_experiments.list [osotolongo@brick03 facehbi]$ head xnat_pet_experiments.list XNAT5_E00276 XNAT5_E00278 XNAT5_E00283 XNAT5_E00296 XNAT5_E00299 XNAT5_E00308 XNAT5_E00316 XNAT5_E00318 XNAT5_E00319 XNAT5_E00323
Y ahora mandamos todo,
[osotolongo@brick03 facehbi]$ for x in `cat xnat_pet_experiments.list`; do xnatapic run_pipeline --project_id facehbi --pipeline RegisterPETwithMRImatch --experiment_id ${x}; done
Troubleshooting
Sacando los PET a ejecutar
¿Que sujetos tengo en el proyecto?
[osotolongo@brick03 f5cehbi]$ xnatapic list_subjects --project_id f5cehbi --label > xnat_subjects.list
¿De aqui, que sujetos tienen MRI?
[osotolongo@brick03 f5cehbi]$ for x in `awk -F"," {'print $1'} xnat_subjects.list`; do e=$(xnatapic list_experiments --project_id f5cehbi --subject_id ${x} --modality MRI); if [[ ${e} ]]; then echo "${x},${e}"; fi; done > xnat_subject_mri.list
¿De estos, cuales tiene PET?
[osotolongo@brick03 f5cehbi]$ for x in `awk -F"," {'print $1'} xnat_subject_mri.list`; do e=$(xnatapic list_experiments --project_id f5cehbi --subject_id ${x} --modality PET); if [[ ${e} ]]; then echo "${x},${e}"; fi; done > xnat_subjects_mri_pet.list
¿De estos PET, cuantos ha sido calculados?
[osotolongo@brick03 f5cehbi]$ awk -F',' '{if($6!="") print $3}' xnat_pet_results.csv | sed 's/"//g' | tail -n +2 > already_done.txt
Y por ultimo, ¿Cuales me falta por calcular?
[osotolongo@brick03 f5cehbi]$ grep -v "`cat already_done.txt`" xnat_subjects_mri_pet.list | awk -F',' '{print $2}' > pet2do.list
Vamos a hacerlos entonces!
[osotolongo@brick03 f5cehbi]$ for x in `cat pet2do.list`; do xnatapic run_pipeline --project_id f5cehbi --pipeline RegisterPETwithMRImatch --experiment_id ${x}; done [osotolongo@brick03 f5cehbi]$ queue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 13027 fast RunFreesurfer.XNAT5_E00001 xnat R 4:35:39 1 brick01 13028 fast RegisterPETwithMRImatch.XNAT5_E00710 xnat R 0:15 1 brick01 13029 fast RegisterPETwithMRImatch.XNAT5_E00729 xnat R 0:15 1 brick01 13030 fast RegisterPETwithMRImatch.XNAT5_E00733 xnat R 0:15 1 brick01 13031 fast RegisterPETwithMRImatch.XNAT5_E00735 xnat R 0:12 1 brick01 13032 fast RegisterPETwithMRImatch.XNAT5_E00737 xnat R 0:12 1 brick01 13033 fast RegisterPETwithMRImatch.XNAT5_E00742 xnat R 0:12 1 brick01 13034 fast RegisterPETwithMRImatch.XNAT5_E00743 xnat R 0:12 1 brick02 13035 fast RegisterPETwithMRImatch.XNAT5_E00746 xnat R 0:12 1 brick02 13036 fast RegisterPETwithMRImatch.XNAT5_E00751 xnat R 0:12 1 brick02 13037 fast RegisterPETwithMRImatch.XNAT5_E00752 xnat R 0:12 1 brick02 13038 fast RegisterPETwithMRImatch.XNAT5_E00753 xnat R 0:12 1 brick02
PET con tag erroneo
Si el tag con que estan etiquetadas las imagenes es incorrecto, el registro de PET dara error. Tipicamente recibes un email con un subject como:
XNAT update: Processing failed for F082A
Habria que revisar el sujeto, mirar como se ha etiquetado la imagen,
y relanzar algo como,
[osotolongo@brick03 f5cehbi]$ xnatapic run_pipeline --project_id f5cehbi --pipeline RegisterPETwithMRImatch --experiment_id XNAT5_E00752 --dcmFBBtag PETNAC_Standard [osotolongo@brick03 f5cehbi]$ queue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 13039 fast RegisterPETwithMRImatch.XNAT5_E00752 xnat R 0:03 1 brick01
failsafe PET
Un escenario que puede ocurrir es cuando el DICOM PET no se convierte correctamente con las herramientas automaticas. Es posible entonces, subir el PET en formato NIfTI-1 y ejecutar un pipeline para que registre este ultimo archivo.
[osotolongo@brick03 f2cehbi]$ xnatapic upload_nifti --project_id f2cehbi --subject_id F043 --experiment_id F043F --scan_id 5 /nas/clinic/nii/v2/F043/PET.nii PET.json
El archivo nifti debe ser el correspondiente al total de tiempo integrado,
[osotolongo@brick03 f2cehbi]$ fslinfo /nas/clinic/nii/v2/F043/PET.nii data_type FLOAT32 dim1 400 dim2 400 dim3 109 dim4 1 datatype 16 pixdim1 1.018210 pixdim2 1.018210 pixdim3 2.027008 pixdim4 0.000000 cal_max 0.0000 cal_min 0.0000 file_type NIFTI-1+
El archivo json debe contener la info minima para identificar el protocolo correcto,
[osotolongo@brick03 f2cehbi]$ cat PET.json { "SeriesDescription": "FACEHBI_Florbetaben_20min", "ProtocolName": "FACEHBI_Florbetaben_20min" }
ambos archivos deben tener el mismo nombre.
Tras esto ya es posible lanzar el pipeline RegisterPETwithMRI,
[osotolongo@brick03 f2cehbi]$ xnatapic run_pipeline --project_id f2cehbi --pipeline RegisterPETwithMRI --experiment_id F043F
PET FBB QC interactuando con XNAT
Making of
El procesamiento de las FBB en XNAT genera una imagen para evaluar la calidad del registro de FBB a espacio MNI.
lo que necesitamos es una herramienta sencilla capaz de leer la información de XNAT, mostrar las imagenes, permitir evaluar el QC y volcar de regreso la info en XNAT.
TIMTOWTDI, pero voy a hacerlo a la old fashion con CGI.pm.
Necesito leer tres cosas por cada sujeto, experiment_ID, imagen de QA y estado del QA. Primero la lista de sujetos del proyecto, con la REST API,
curl -X GET -u "$USER:$PASSWD" "$HOST/data/projects/$PROJECT/subjects?format=json" | jq ".ResultSet.Result[].ID" | sed \'s/"/,/g\'
Ahora por cada sujeto saco el experimento PET que le corresponde,
curl -X GET -u "$USER:$PASSWD" "$HOST/data/projects/$PROJECT/subjects/$SUBJECT/experiments?xsiType=xnat:petSessionData" 2>/dev/null | jq ".ResultSet.Result[].ID" | sed \'s/"//g\'
Para este experimento obtengo el QA,
curl -X GET -u "$USER:$PASSWD" "$HOST/data/experiments/$EXPERIMENT/resources/MRI/files/mriSessionMatch.json" 2>/dev/null | jq ".ResultSet.Result[].qa"
y me bajo la imagen a un directorio temporal,
curl -X GET -u "$USER:$PASSWD" "$HOST/data/experiments/$EXPERIMENT/resources/MRI/files/$SUBJECT_fbb_mni.gif" -o $TMP_IMAGE
Todo esto lo voy metiendo en un hash y lo pongo en un formulario con la CGI. Cuando se envia el formulario tengo que crear el json con la info y luego subirlo. Pero lo que voy a hacer es bajar el json existente, cambiar el valor de QA y volverlo a subir. Algo asi,
curl -X GET -u "$USER:$PASSWD" "$HOST/data/experiments/$EXPERIMENT/resources/MRI/files/mriSessionMatch.json" 2>/dev/null
esto lo meto en una variable y le hago,
$resp =~ s/,"qa":\d,/"qa":$qcs{$xpx},/;
la escribo a un archivo temporal y la subo con,
curl -X PUT -u "$USER:$PASSWD" "$HOST/data/experiments/$EXPERIMENT/resources/MRI/files/mriSessionMatch.json?overwrite=true" -F file="@$TMP_FILE"
y ya esta!!!!! ponemos un smiley o algo. el codigo en github.
Usando esto
El output es feo y lento, pero facil de usar. Primero hay que suministrar el nombre del proyecto en XNAt y los datos de login para XNAT.
La aplicacion se conectara entonces usando la REST API y mostrara el resultado del QC que tenemos. Aqui se modifica los necesario, se le da a submit y ya esta.
Nota: no hay que ser muy exigente con el resutado del registro. Hay mucho smooth y ROIs grandes para compensar los pequeños desplazamiento. on que la cabeza este mas o menos en su sitio ya nos vale.
Extraer resultados
La idea fundamental aqui es obtener los valores de SUVR y centiloide calculados en XNAT. Estos pueden obtenerse con,
$ xnatapic get_registration_report --project_id f5cehbi --output xnat_pet_results.csv
y esto vamos a limpiarlo un poco,
$ awk -F"," '{print $2","$6","$7}' xnat_pet_results.csv | sed 's/"//g' | tail -n +2 | sort -t, -k 1 > pet.results
La lista de sujetos del proyecto se obtiene con,
$ xnatapic list_subjects --project_id f5cehbi --label > xnat_subjects.list
Esto se puede ordenar rapidamente haciendo,
$ sort -t, -k 1 xnat_subjects.list > xnat_subjects_sorted.list
Y entonces podemos integrar los ID de proyecto con los resultaos, a traves de los ID de XNAT, y seleccionar los datos que queremos guardar,
$ join -t, xnat_subjects_sorted.list pet.results | sort -t, -k 2 | awk -F"," '{if ($3) print $2";"$3";"$4}' | sed '1iSubject;SUVR;Centiloid'"
Todo esto se resume en el script xnat_pullcl.pl. Los archivos intermedios se borran una vez que se obtienen los resultados. Las opciones son,
- -p : nombre del proyecto en XNAT, se ignora si existe -x. Solo existe por compatibilidad.
- -x : nombre del proyecto en XNAT
- -o : archivo de salida (default STDOUT)
PET-tau
Formato de resultados
Informe final en formato de entrega a partir de XNAT (MRI)
Necesitamos varias entradas para crear el archivo final
resultados de FS
[osotolongo@brick03 facehbi]$ ls fsrecon/*.csv fsrecon/aparc_area_lh.csv fsrecon/aparc_thickness_lh.csv fsrecon/aparc_volume_lh.csv fsrecon/aseg_stats.csv fsrecon/aparc_area_rh.csv fsrecon/aparc_thickness_rh.csv fsrecon/aparc_volume_rh.csv fsrecon/wmparc_stats.csv
a ver como podemos bajarnos esto de XNAT,
[osotolongo@brick03 facehbi]$ xnatapic list_subjects --project_id facehbi --label > xnat_subjects.csv [osotolongo@brick03 facehbi]$ while read -r line; do stag=$(echo ${line} | awk -F"," '{print $1}'); slab=$(echo ${line} | awk -F"," '{print $2}'); xtag=$(xnatapic list_experiments --project_id facehbi --subject_id ${stag} --modality MRI --date); echo "${slab},${xtag}"; done < xnat_subjects.csv > exps_withdate.csv [osotolongo@brick03 facehbi]$ while read -r line; do xp=$(echo ${line} | awk -F"," '{print $2}'); slab=$(echo ${line} | awk -F"," '{print $1}'); mkdir -p test_xnatfs/${xp}/stats; xnatapic get_fsresults --experiment_id ${xp} --all-stats test_xnatfs/${xp}/stats; done < exps_withdate.csv
Y ahi esta todo pero ahora hay que parsear cada archivo. Por ejemplo para asegs habria que hacer,
[osotolongo@brick03 facehbi]$ ls test_xnatfs/ > test_subjects.txt [osotolongo@brick03 facehbi]$ asegstats2table --sd=/nas/data/facehbi/test_xnatfs/ --subjectsfile=test_subjects.txt -t test_asegs.txt [osotolongo@brick03 facehbi]$ sed 's/\t/,/g' test_asegs.txt > test_asegs.csv
La función fs_file_metrics() en las bibliotecas del pipeline, define los archivos y comandos correspondientes para sacar los resultados. Asi que una manera es hacer esto en Perl y ejecutar todo en un espacio “no real” con todo escrito en directorios temporales. Albert Laporra
Vayamos por partes Jack the ripper,
Primero obtenemos los sujetos del proyecto,
my $subjects_list = mktemp($tmp_dir.'/sbjsfileXXXXX'); my $order = 'xnatapic list_subjects --project_id '.$study.' --label > '.$subjects_list;
ahora recorremos esta lista y sacamos las MRI asociadas y las fechas en que se han hecho,
my ($stag, $slab) = /(.*),(.*)/; chomp($slab); $guys{$slab}{'XNATSBJ'} = $stag; my $xnat_order = 'xnatapic list_experiments --project_id '.$study.' --subject_id '.$stag.' --modality MRI --date'; my $xtag = qx/$xnat_order/; chomp($xtag); my ($xnam, $xdate) = $xtag =~ /(.*),(.*)/; $guys{$slab}{'XNATEXP'} = $xnam; $guys{$slab}{'DATE'} = $xdate;
y para cada experiento gurdamos los resultados del analisis de FS en un directorio,
my $outdir = $fsoutput.'/'.$plab.'/stats'; make_path $outdir; $order = 'xnatapic get_fsresults --experiment_id '.$guys{$plab}{'XNATEXP'}.' --all-stats '.$outdir; system($order);
Si ahora engañamos al sistema, cambiado de sitio el SUBJECTS_DIR,
my %stats = fs_file_metrics(); $ENV{'SUBJECTS_DIR'} = $fsoutput; my $fsout = $fsoutput.'/fsrecon'; make_path $fsout; </code perl> podemos utilizar las sintaxis de la funcion //fs_file_metrics()// almacenadas en [[neuroimagen:neuro4.pm#fsmetricspm|FSMetrics.pm]]. //L ultima version actualizada, siempre [[https://github.com/asqwerty666/acenip/blob/main/lib/FSMetrics.pm|en github]]//. <code perl> if(exists($stats{$stat}{'active'}) && $stats{$stat}{'active'}){ (my $order = $stats{$stat}{'order'}) =~ s/<list>/$fslist/; $order =~ s/<fs_output>/$fsout/; system("$order"); (my $opatt = $stat) =~ s/_/./g; $opatt =~ s/(.*)\.rh$/rh\.$1/; $opatt =~ s/(.*)\.lh$/lh\.$1/; $order = 'sed \'s/\t/,/g; s/^Measure:volume\|^'.$opatt.'/Subject/\' '.$fsout.'/'.$stat.'.txt > '.$fsout.'/'.$stat.'.csv'."\n"; system($order); }
Ahora tenemos que bajarnos el QC, pero esto ya lo tenemos implementado en xnatapic.
my $fsqcfile = $fsoutput.'/fsqc.csv'; $order = 'xnatapic get_fsqc --project_id '.$study.' --output '.$fsqcfile; system($order); open QCF, "<$fsqcfile"; while (<QCF>) { my ($sbj, $qcok, $qcnotes) = /(.*), "(.*)", "(.*)"/; $qcok =~ tr/ODILg/odilG/; $guys{$sbj}{'FSQC'} = $qcok; $guys{$sbj}{'Notes'} = $qcnotes; } close QCF;
Ya tenemos toda la info asi que ahora lo metemos en un spreadsheet y se acabo. Ver codigo completo en github
Para sacar el report solo hay que suministrar la lista de internos y el nombre del proyecto en XNAT,
$ fs_metrics_xnat.pl -i internos.csv facehbi
El archivo de resultados tiene un nombre del estilo: facehbi_fsmetrics_20211020_170114.xls
Informe final en formato de entrega a partir de XNAT (PET-FBB)
En la nueva versión del pipeline, el procesamiento básico del FBB se hace dentro de XNAT. Todo lo necesario para realizar el informe final, excepto los codigos internos se guarda dentro de la DB de XNAT, asi que utilizando xnatapic y con un poco de organizacion se puede elaborar directamente el informe final.
Primero sacamos la lista de sujetos del proyecto,
my $subjects_list = mktemp($tmp_dir.'/sbjsfileXXXXX'); my $order = 'xnatapic list_subjects --project_id '.$study.' --label > '.$subjects_list; system($order);
y para cada sujeto encontramos el experimento FBB correspondiente, y al mismo tiempo guardamos la fecha en que se hizo,
open SLF, "<$subjects_list"; while(<SLF>){ my ($stag, $slab) = /(.*),(.*)/; chomp($slab); $guys{$slab}{'XNATSBJ'} = $stag; my $xnat_order = 'xnatapic list_experiments --project_id '.$study.' --subject_id '.$stag.' --modality PET --date'; my $xtag = qx/$xnat_order/; chomp($xtag); if($xtag){ my ($xnam, $xdate) = $xtag =~ /(.*),(.*)/; $guys{$slab}{'XNATEXP'} = $xnam; #$xdate =~ s/-/./g; $guys{$slab}{'DATE'} = $xdate; } } close SLF; unlink $subjects_list;
Ahora leemos los codigos internos,
if ($internos){ open IIF, "<$internos"; while (<IIF>){ if (/.*,\d{8}$/){ my ($sbj, $interno) = /(.*),(\d{8})$/; $guys{$sbj}{'INTERNO'} = $interno; } } close IIF; print GDF "Subject,Interno,Date\n"; foreach my $plab (sort keys %guys){ if (exists($guys{$plab}{'INTERNO'}) and exists($guys{$plab}{'DATE'})){ print GDF "$plab,$guys{$plab}{'INTERNO'},$guys{$plab}{'DATE'}\n"; print "$plab,$guys{$plab}{'INTERNO'},$guys{$plab}{'DATE'}\n"; } } }
y la info del procesamiento,
my $fbbout = tempdir(TEMPLATE => $tmp_dir.'/fsout.XXXXX', CLEANUP => 1); my $fbfile = $fbbout.'/fbbcl.csv'; $order = 'xnatapic get_fbbcl --project_id '.$study.' --output '.$fbfile; system($order); open CLF, "<$fbfile"; while(<CLF>){ if(/, \d$/){ my ($sbj, $suvr, $cl, $qc) = /(.*), (.*), (.*), (.*)$/; $guys{$sbj}{'SUVR'} = $suvr; $guys{$sbj}{'CL'} = $cl; $guys{$sbj}{'QC'} = $qcpass[$qc]; } } close CLF;
Todo junto lo guardamos en formato de MS Excel,
my $info = csv (in => $info_page); my $workbook = Spreadsheet::Write->new(file => $ofile, sheet => 'Info'); for my $i (0 .. $#{$info}) { my $row = $info->[$i]; $workbook->addrow($row); } #now regroup data $workbook->addsheet('FBB Centiloid'); my @drow; if($internos){ @drow = split ',', "Subject,Interno,Date,SUVR,CL,QC"; }else{ @drow = split ',', "Subject,Date,SUVR,CL,QC"; } $workbook->addrow(\@drow); foreach my $sbj (sort keys %guys){ if(exists($guys{$sbj}) and exists($guys{$sbj}{'SUVR'}) and $guys{$sbj}{'SUVR'} and ($guys{$sbj}{'SUVR'} ne 'null')){ if($internos){ @drow = split ',', "$sbj,$guys{$sbj}{'INTERNO'},$guys{$sbj}{'DATE'},$guys{$sbj}{'SUVR'},$guys{$sbj}{'CL'},$guys{$sbj}{'QC'}"; }else{ @drow = split ',', "$sbj,$guys{$sbj}{'DATE'},$guys{$sbj}{'SUVR'},$guys{$sbj}{'CL'},$guys{$sbj}{'QC'}"; } $workbook->addrow(\@drow); } } $workbook->close();
El codigo completo, incluyendo algun tratamiento de excepciones extra en github.
Para ejecutarlo es tan simple como hacer algo asi,
$ fbb_cl_metrics_xnat.pl -i internos.csv f5cehbi
El resultado es un archivo conun nombre como: f5cehbi_fbb_cl_metrics_20211001_110802.xls
pipeline
Aqui se trata de sintetizar las ideas de Formato de entrega de los resultados de analisis
El objetivo es proporcionar los resultados finales del analisis en el formato de intercambio para neurologia. Basicamente un archivo de MS excel con los datos de ID en proyecto, numero de historia clinica, fecha del scan y datos generales del procesamiento.
Datos del sujeto
Es necesario diponer primero de un archivo con este formato,
[osotolongo@detritus facehbi]$ head gdata_mri.csv PSubject,Subject,Interno,Date F001,0001,20090806,05.12.2014 F002,0002,20131084,05.12.2014 F003,0003,20130456,11.12.2014 F004,0004,20080130,12.12.2014 F005,0005,20141272,07.01.2015 F006,0006,20141107,23.12.2014 F007,0007,20080716,19.12.2014 F008,0008,20131483,20.12.2014 F009,0009,20141277,10.01.2015
Este es el archivo guia para enlazar los resultados. Los datos son, en orden,
- PSubject: ID del sujeto en el proyecto
- Subject: ID de procesamiento
- Interno: Numero de hisoria clinica
- Date: Fecha del scanner
Informacion del procesamiento
La informacion del procesamiento consiste en datos de contacto de quien realiza el procesamiento, datos de contacto de quien realiza el scanner, info de general de las variables y demas notas que se quieran agregar. Esta sera la portada del archivo de datos.
Ejemplo,
[osotolongo@detritus facehbi]$ cat info_page_dti.csv ,, ,, Base de datos:,O. Sotolongo-Grau,asqwerty@gmail.com Extracción de métricas:,O. Sotolongo-Grau,asqwerty@gmail.com col. Externa:,Assumpta Vivas-Larruy,assumpta.vivas@gmail.com ,Miguel Ángel Tejero,mtejeroc@corachan.com
Directorio de resultados
Todos los resultados que se deseen incluir en el archivo de salida deben estar dentro del mismo directorio, creado exprofeso, y en correcto formato CSV. Elnombre del archivo sera el nombre de la hojka de datos. Los archivos de salida del pipeline no salen en este formato por lo que habra que convertirlos. Ejemplo,
[osotolongo@detritus facehbi]$ sed 's/;/,/g' facehbi_dti_DMN.csv > dti_results/DMN.csv [osotolongo@detritus facehbi]$ sed 's/;/,/g' facehbi_dti_FPCustom.csv > dti_results/FPCustom.csv
Uniendo todo
Lo que se debe hacer ahora es unir todos los datos y convertirlos ordenados.
el procedimiento es sencillo pero lleva mucho control de errores
Call
Para ejecutarlo se deben incluir todos los datos en la linea de comandos,
- -i: directorio con los resultados (obligatorio)
- -o: nombre del rchivo de salida
- -g: nombre del archivo guia (obligatorio)
- -s: nombre del archivo de informacion general
- nombre del proyecto (obligatorio)
Ejemplo,
[osotolongo@detritus facehbi]$ metrics2xls.pl -i dti_results -g gdata_mri.csv -o dti_tracks.xlsx -s info_page_dti.csv facehbi
y ya esta, la salida en un archivo excel con todos los datos.