User Tools

Site Tools


neuroimagen:pipe05

This is an old revision of the document!


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 DELETEME
  • 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 github DONE (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. DONE
  • Mejorar 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 Notes DONE (Update Freesurfer 7.2)

TODO

  1. acenip Containers? DELETEME

Dependencias

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,

  1. NAME: El nombre del proyecto
  2. SRC_PATH: La ruta donde se encuentran los archivos fuentes del proyecto (DICOMs)
  3. PROJ_PATH: La ruta donde se ejecuta el procesamiento, se guardan archivos intemedios y resultados.

Cada sujeto se caracteriza por,

  1. PID: identificador dentro del proyecto. Enlaza todos los datos del sujeto entre si.
  2. NID: identificador dentro del procesamiento de neuroimagen. Identifica los datos de cada sujeto dentro del proyecto.
  3. 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,

  1. make_proj.pl → creacion del proyecto
  2. update_mri_db.pl → creacion y actualizacion de la DB del proyecto.
  3. 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/

Ejemplo

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 :ALERT:


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

con epi_reg

[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

El QC no cambia

[tester@detritus ptest]$ make_dti_report.pl ptest

DTI metrics (Atlas)

Esto tampoco cambia demasiado, pero se aprovechan las subs nuevas y se simplifica la ubicacion de los archivos

[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,

  1. Cambiar el script de metricas de TRACULA para incluir el volumen de los tractos
  2. 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

Queda bastante sencillo ahora

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. bedtrack_hippocampus

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.

bedtrack_LN

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,

Todo muy basico

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 :-P

ica_rs_0001

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.

Bien Aceptable Mal

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.

neuroimagen/pipe05.1641811551.txt.gz · Last modified: 2022/01/10 10:45 by osotolongo