gemprf 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gemprf-0.1.1/LICENSE +28 -0
- gemprf-0.1.1/MANIFEST.in +22 -0
- gemprf-0.1.1/PKG-INFO +98 -0
- gemprf-0.1.1/README.md +74 -0
- gemprf-0.1.1/gem/__init__.py +10 -0
- gemprf-0.1.1/gem/analysis/__init__.py +6 -0
- gemprf-0.1.1/gem/analysis/prf_analysis.py +72 -0
- gemprf-0.1.1/gem/analysis/prf_r2_variance_explain.py +101 -0
- gemprf-0.1.1/gem/configs/__init__.py +6 -0
- gemprf-0.1.1/gem/configs/analysis_configs/analysis_additional_params.h5 +0 -0
- gemprf-0.1.1/gem/configs/analysis_configs/analysis_config.xml +124 -0
- gemprf-0.1.1/gem/configs/config_manager.py +174 -0
- gemprf-0.1.1/gem/configs/default_config/default_config - old before concatenation.xml +141 -0
- gemprf-0.1.1/gem/configs/default_config/default_config.xml +171 -0
- gemprf-0.1.1/gem/configs/default_config/new_concatenationDummyTest_config.xml +180 -0
- gemprf-0.1.1/gem/configs/default_config/new_concatenation_config.xml +180 -0
- gemprf-0.1.1/gem/configs/gem_xml_utils.py +30 -0
- gemprf-0.1.1/gem/configs/multiproc_prfspace_config/asus_analysis_config.xml +165 -0
- gemprf-0.1.1/gem/configs/multiproc_prfspace_config/dgx_analysis_config.xml +165 -0
- gemprf-0.1.1/gem/data/__init__.py +6 -0
- gemprf-0.1.1/gem/data/bids_handler.py +208 -0
- gemprf-0.1.1/gem/data/gem_bids_concatenation_data_info.py +42 -0
- gemprf-0.1.1/gem/data/gem_bids_individual_run_data_info.py +35 -0
- gemprf-0.1.1/gem/data/gem_stimulus_file_info.py +16 -0
- gemprf-0.1.1/gem/data/observed_data.py +42 -0
- gemprf-0.1.1/gem/fitting/__init__.py +6 -0
- gemprf-0.1.1/gem/fitting/hpc_coefficient_matrix.py +188 -0
- gemprf-0.1.1/gem/fitting/hpc_grid_fit.py +184 -0
- gemprf-0.1.1/gem/fitting/hpc_refine_fit.py +632 -0
- gemprf-0.1.1/gem/init_setup.py +136 -0
- gemprf-0.1.1/gem/kernels/gaussian_kernel.cu +208 -0
- gemprf-0.1.1/gem/kernels/gaussian_kernel.ptx +1408 -0
- gemprf-0.1.1/gem/model/__init__.py +6 -0
- gemprf-0.1.1/gem/model/prf_DoG_model.py +32 -0
- gemprf-0.1.1/gem/model/prf_gaussian_model.py +121 -0
- gemprf-0.1.1/gem/model/prf_model.py +130 -0
- gemprf-0.1.1/gem/model/prf_stimulus.py +146 -0
- gemprf-0.1.1/gem/model/selected_prf_model.py +17 -0
- gemprf-0.1.1/gem/run/__init__.py +0 -0
- gemprf-0.1.1/gem/run/run_gem_prf_analysis.py +728 -0
- gemprf-0.1.1/gem/run_gem.py +42 -0
- gemprf-0.1.1/gem/signals/__init__.py +6 -0
- gemprf-0.1.1/gem/signals/hrf_generator.py +64 -0
- gemprf-0.1.1/gem/signals/orthogonalization_matrix.py +40 -0
- gemprf-0.1.1/gem/signals/signal_synthesizer.py +281 -0
- gemprf-0.1.1/gem/space/PRFNeighbours.py +4 -0
- gemprf-0.1.1/gem/space/PRFSpace.py +569 -0
- gemprf-0.1.1/gem/space/__init__.py +6 -0
- gemprf-0.1.1/gem/space/coefficient_matrix.py +43 -0
- gemprf-0.1.1/gem/tools/__init__.py +6 -0
- gemprf-0.1.1/gem/tools/json_file_operations.py +43 -0
- gemprf-0.1.1/gem/utils/__init__.py +6 -0
- gemprf-0.1.1/gem/utils/gem_gpu_manager.py +107 -0
- gemprf-0.1.1/gem/utils/gem_h5_file_handler.py +24 -0
- gemprf-0.1.1/gem/utils/gem_load_estimations.py +89 -0
- gemprf-0.1.1/gem/utils/gem_write_to_file.py +121 -0
- gemprf-0.1.1/gem/utils/hpc_cupy_utils.py +149 -0
- gemprf-0.1.1/gem/utils/logger.py +52 -0
- gemprf-0.1.1/gemprf.egg-info/PKG-INFO +98 -0
- gemprf-0.1.1/gemprf.egg-info/SOURCES.txt +63 -0
- gemprf-0.1.1/gemprf.egg-info/dependency_links.txt +1 -0
- gemprf-0.1.1/gemprf.egg-info/requires.txt +12 -0
- gemprf-0.1.1/gemprf.egg-info/top_level.txt +2 -0
- gemprf-0.1.1/pyproject.toml +40 -0
- gemprf-0.1.1/setup.cfg +4 -0
gemprf-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2025, Siddharth Mittal, Medical University of Vienna
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
gemprf-0.1.1/MANIFEST.in
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Include package data (ONLY specify the non-python files that need to be included)
|
|
2
|
+
# Include config files
|
|
3
|
+
recursive-include gem/configs *.xml *.h5
|
|
4
|
+
|
|
5
|
+
# Include CUDA kernels
|
|
6
|
+
recursive-include gem/kernels *.cu *.ptx
|
|
7
|
+
|
|
8
|
+
# Exclude tests and test data
|
|
9
|
+
recursive-exclude gem/tests *
|
|
10
|
+
recursive-exclude gem/tests/temp *
|
|
11
|
+
recursive-exclude gem/tests/testdata *
|
|
12
|
+
|
|
13
|
+
# Exclude cache and compiled artifacts
|
|
14
|
+
recursive-exclude gem/__pycache__ *
|
|
15
|
+
recursive-exclude __pycache__ *
|
|
16
|
+
recursive-exclude gem/**/*.pyc
|
|
17
|
+
recursive-exclude gem/**/*.pyo
|
|
18
|
+
recursive-exclude gem/**/*.nbc
|
|
19
|
+
recursive-exclude gem/**/*.nbi
|
|
20
|
+
|
|
21
|
+
# Misc OS garbage
|
|
22
|
+
exclude .DS_Store
|
gemprf-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gemprf
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A Python library for population receptive field (pRF) analysis
|
|
5
|
+
Author-email: Siddharth Mittal <siddharth.mittal@meduniwien.ac.at>
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
Project-URL: Homepage, https://gemprf.github.io/
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: h5py==3.13.0
|
|
12
|
+
Requires-Dist: joblib==1.4.2
|
|
13
|
+
Requires-Dist: matplotlib==3.10.1
|
|
14
|
+
Requires-Dist: nibabel==5.3.2
|
|
15
|
+
Requires-Dist: numba==0.61.0
|
|
16
|
+
Requires-Dist: numba_kdtree==0.6.0
|
|
17
|
+
Requires-Dist: numpy==2.1.3
|
|
18
|
+
Requires-Dist: nvidia_ml_py==12.570.86
|
|
19
|
+
Requires-Dist: pandas==2.2.3
|
|
20
|
+
Requires-Dist: pynvml==12.0.0
|
|
21
|
+
Requires-Dist: scipy==1.15.2
|
|
22
|
+
Requires-Dist: xmltodict==0.14.2
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
Welcome to **GEM-pRF** - a standalone, plug-and-play software for population receptive field (pRF) mapping, designed for **large-scale data analysis with high accuracy**.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
To understand the theoretical foundations and details of how the software works, please refer to our paper: 👉[Mittal et al (2025), ](https://www.biorxiv.org/content/10.1101/2025.05.16.654560v1)*[GEM-pRF: GPU-Empowered Mapping of Population Receptive Fields for Large-Scale fMRI Analysis](https://www.biorxiv.org/content/10.1101/2025.05.16.654560v1)*
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## Documentation
|
|
32
|
+
|
|
33
|
+
An official documentation is coming soon ([GEM-pRF documentation link](https://gemprf.github.io/))! Meanwhile, to get the mathematical foundation of the software, you may refer to the [GEM-pRF paper](https://www.biorxiv.org/content/10.1101/2025.05.16.654560v1).
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
GEM-pRF requires the GPU access for the data processing. At the moment, GEM uses CUDA libraries to acess/process data on NVIDIA GPUs.
|
|
39
|
+
|
|
40
|
+
> \[!WARNING\]
|
|
41
|
+
>
|
|
42
|
+
> Please check your system has compatible NVIDIA GPU available.
|
|
43
|
+
|
|
44
|
+
### Step-by-Step Guide
|
|
45
|
+
|
|
46
|
+
**Step 1. Install dependencies**
|
|
47
|
+
|
|
48
|
+
* Create or activate your preferred Python/Conda environment.
|
|
49
|
+
* Install all required dependencies listed in `requirements.txt`:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -r requirements.txt
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
**Step 2. Download GEM-pRF code**
|
|
57
|
+
|
|
58
|
+
* Clone the repository:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/siddmittal/GEMpRF.git
|
|
62
|
+
cd GEMpRF
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Running GEM-pRF
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
> \[!CAUTION\]
|
|
70
|
+
> Before proceeding, make sure to install the required python dependencies as specified in the `requirements.txt` file
|
|
71
|
+
|
|
72
|
+
GEM-pRF is written as a **standalone software**. It comes with an XML configuration file. Once you configure your XML file (see [sample config](https://github.com/siddmittal/GEMpRF/blob/main/gem/configs/analysis_configs/analysis_config.xml)), you can directly run the software.
|
|
73
|
+
|
|
74
|
+
### 🔹 **Option A: Run from terminal**
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
1. Open a terminal (e.g. Anaconda Prompt).
|
|
80
|
+
2. Activate the environment with the dependencies installed.
|
|
81
|
+
3. Navigate to the GEM-pRF folder.
|
|
82
|
+
4. Run:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
python run_gem.py PATH_TO_YOUR_XML_CONFIG_FILE
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
### 🔹 **Option B: Run from IDE (e.g. VS Code)**
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
1. Open the downloaded GEM-pRF folder in VS Code.
|
|
95
|
+
2. Edit the `run_gem.py` script to specify the path to your XML config file.
|
|
96
|
+
3. Run the script directly from the IDE.
|
|
97
|
+
|
|
98
|
+
|
gemprf-0.1.1/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Welcome to **GEM-pRF** - a standalone, plug-and-play software for population receptive field (pRF) mapping, designed for **large-scale data analysis with high accuracy**.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
To understand the theoretical foundations and details of how the software works, please refer to our paper: 👉[Mittal et al (2025), ](https://www.biorxiv.org/content/10.1101/2025.05.16.654560v1)*[GEM-pRF: GPU-Empowered Mapping of Population Receptive Fields for Large-Scale fMRI Analysis](https://www.biorxiv.org/content/10.1101/2025.05.16.654560v1)*
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
An official documentation is coming soon ([GEM-pRF documentation link](https://gemprf.github.io/))! Meanwhile, to get the mathematical foundation of the software, you may refer to the [GEM-pRF paper](https://www.biorxiv.org/content/10.1101/2025.05.16.654560v1).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
GEM-pRF requires the GPU access for the data processing. At the moment, GEM uses CUDA libraries to acess/process data on NVIDIA GPUs.
|
|
15
|
+
|
|
16
|
+
> \[!WARNING\]
|
|
17
|
+
>
|
|
18
|
+
> Please check your system has compatible NVIDIA GPU available.
|
|
19
|
+
|
|
20
|
+
### Step-by-Step Guide
|
|
21
|
+
|
|
22
|
+
**Step 1. Install dependencies**
|
|
23
|
+
|
|
24
|
+
* Create or activate your preferred Python/Conda environment.
|
|
25
|
+
* Install all required dependencies listed in `requirements.txt`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install -r requirements.txt
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
**Step 2. Download GEM-pRF code**
|
|
33
|
+
|
|
34
|
+
* Clone the repository:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/siddmittal/GEMpRF.git
|
|
38
|
+
cd GEMpRF
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## Running GEM-pRF
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
> \[!CAUTION\]
|
|
46
|
+
> Before proceeding, make sure to install the required python dependencies as specified in the `requirements.txt` file
|
|
47
|
+
|
|
48
|
+
GEM-pRF is written as a **standalone software**. It comes with an XML configuration file. Once you configure your XML file (see [sample config](https://github.com/siddmittal/GEMpRF/blob/main/gem/configs/analysis_configs/analysis_config.xml)), you can directly run the software.
|
|
49
|
+
|
|
50
|
+
### 🔹 **Option A: Run from terminal**
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
1. Open a terminal (e.g. Anaconda Prompt).
|
|
56
|
+
2. Activate the environment with the dependencies installed.
|
|
57
|
+
3. Navigate to the GEM-pRF folder.
|
|
58
|
+
4. Run:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
python run_gem.py PATH_TO_YOUR_XML_CONFIG_FILE
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### 🔹 **Option B: Run from IDE (e.g. VS Code)**
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
1. Open the downloaded GEM-pRF folder in VS Code.
|
|
71
|
+
2. Edit the `run_gem.py` script to specify the path to your XML config file.
|
|
72
|
+
3. Run the script directly from the IDE.
|
|
73
|
+
|
|
74
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
"@Author : Siddharth Mittal",
|
|
5
|
+
"@Version : 1.0",
|
|
6
|
+
"@Contact : siddharth.mittal@meduniwien.ac.at",
|
|
7
|
+
"@License : (C)Copyright 2024, Medical University of Vienna",
|
|
8
|
+
"@Desc : None",
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
import cupy as cp
|
|
14
|
+
from typing import List
|
|
15
|
+
|
|
16
|
+
from gem.model.prf_model import PRFModel
|
|
17
|
+
from gem.model.selected_prf_model import SelectedPRFModel
|
|
18
|
+
from gem.model.prf_stimulus import Stimulus
|
|
19
|
+
from gem.space.PRFSpace import PRFSpace
|
|
20
|
+
from gem.utils.hpc_cupy_utils import HpcUtils as gpu_utils
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PRFAnalysis():
|
|
24
|
+
def __init__(self, prf_space : PRFSpace, stimulus : Stimulus) -> None:
|
|
25
|
+
self.__prf_points = prf_space
|
|
26
|
+
self.__stimulus = stimulus
|
|
27
|
+
self.__model_signals_batches = None
|
|
28
|
+
self.__dervatives_signals_batches_list = None
|
|
29
|
+
self.__error_e = None
|
|
30
|
+
self.__error_de_dtheta_list = None # contains a list of all derivative errors w.r.t each parameter
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def prf_points(self)-> PRFSpace:
|
|
34
|
+
return self.__prf_points
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def stimulus(self)-> Stimulus:
|
|
38
|
+
return self.__stimulus
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def orthonormalized_S_batches(self)-> List[cp.ndarray]:
|
|
42
|
+
return self.__model_signals_batches
|
|
43
|
+
|
|
44
|
+
@orthonormalized_S_batches.setter
|
|
45
|
+
def orthonormalized_S_batches(self, new_value)-> None:
|
|
46
|
+
self.__model_signals_batches = new_value
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def orthonormalized_dS_dtheta_batches_list(self)-> List[List[cp.ndarray]]:
|
|
50
|
+
return self.__dervatives_signals_batches_list
|
|
51
|
+
|
|
52
|
+
@orthonormalized_dS_dtheta_batches_list.setter
|
|
53
|
+
def orthonormalized_dS_dtheta_batches_list(self, new_value)-> None:
|
|
54
|
+
self.__dervatives_signals_batches_list = new_value
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def error_e(self)-> cp.ndarray:
|
|
58
|
+
return self.__error_e
|
|
59
|
+
|
|
60
|
+
@error_e.setter
|
|
61
|
+
def error_e(self, new_value)-> None:
|
|
62
|
+
self.__error_e = new_value
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def error_de_dtheta_list(self)-> List[cp.ndarray]:
|
|
66
|
+
return self.__error_de_dtheta_list
|
|
67
|
+
|
|
68
|
+
@error_de_dtheta_list.setter
|
|
69
|
+
def error_de_dtheta_list(self, new_value)-> None:
|
|
70
|
+
self.__error_de_dtheta_list = new_value
|
|
71
|
+
|
|
72
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import cupy as cp
|
|
3
|
+
from gem.tools.json_file_operations import JsonMgr
|
|
4
|
+
from gem.utils.hpc_cupy_utils import HpcUtils as Utils
|
|
5
|
+
from gem.model import prf_model
|
|
6
|
+
from gem.signals.signal_synthesizer import SignalSynthesizer
|
|
7
|
+
from gem.model.prf_model import GaussianModelParams
|
|
8
|
+
from gem.utils.gem_gpu_manager import GemGpuManager as ggm
|
|
9
|
+
|
|
10
|
+
class R2:
|
|
11
|
+
@classmethod
|
|
12
|
+
def get_r2_new_method_with_epsilon_as_Fx(cls, Y_signals_gpu, O_gpu, epsilon_results_cpu):
|
|
13
|
+
r2 = []
|
|
14
|
+
R_Rt_gpu = cp.eye(O_gpu.shape[0]) - O_gpu
|
|
15
|
+
|
|
16
|
+
num_y_signals = len(epsilon_results_cpu)
|
|
17
|
+
for yIdx in range (num_y_signals):
|
|
18
|
+
y = Y_signals_gpu[:, yIdx]
|
|
19
|
+
yty = y.T @ y
|
|
20
|
+
ystar = O_gpu @ y
|
|
21
|
+
ystarT_ystar_inv = (ystar.T @ ystar) ** (-1)
|
|
22
|
+
e = (float(epsilon_results_cpu[yIdx])) ** 2 #<----------------------------------
|
|
23
|
+
yt_RRt_y = (y.T @ R_Rt_gpu) @ y
|
|
24
|
+
r2_gpu = 1 - ((yty - e - yt_RRt_y) * ystarT_ystar_inv)
|
|
25
|
+
r2.append(float(r2_gpu))
|
|
26
|
+
|
|
27
|
+
return r2
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def get_r2_num_den_method_with_epsilon_as_yTs(cls, Y_signals_gpu, O_gpu, refined_matching_results, refined_S_cpu):
|
|
31
|
+
with cp.cuda.Device(ggm.get_instance().default_gpu_id):
|
|
32
|
+
numerators_gpu , denominators_gpu = cls.get_r2_numerator_denominator_terms(Y_signals_gpu, O_gpu, refined_matching_results, refined_S_cpu)
|
|
33
|
+
r2_results_gpu = 1 - (numerators_gpu / denominators_gpu)
|
|
34
|
+
|
|
35
|
+
return cp.asnumpy(r2_results_gpu)
|
|
36
|
+
|
|
37
|
+
@classmethod # R2 numerator = (yty - e - yt_RRt_y)
|
|
38
|
+
def get_r2_numerator_denominator_terms(cls, Y_signals_gpu, O_gpu, refined_matching_results, refined_signals_cpu: np.ndarray):
|
|
39
|
+
with cp.cuda.Device(ggm.get_instance().default_gpu_id):
|
|
40
|
+
refined_signals_gpu = cp.asarray(refined_signals_cpu)
|
|
41
|
+
num_y_signals = Y_signals_gpu.shape[1]
|
|
42
|
+
|
|
43
|
+
R_Rt_gpu = cp.eye(O_gpu.shape[0]) - O_gpu
|
|
44
|
+
|
|
45
|
+
# Compute yty for each signal
|
|
46
|
+
yty = cp.sum(Y_signals_gpu ** 2, axis=0)
|
|
47
|
+
|
|
48
|
+
# Compute ystar and ystarT_ystar
|
|
49
|
+
ystar = O_gpu @ Y_signals_gpu
|
|
50
|
+
ystarT_ystar = cp.sum(ystar ** 2, axis=0)
|
|
51
|
+
|
|
52
|
+
# Check for NaN refined results
|
|
53
|
+
nan_mask = np.isnan(refined_matching_results).all(axis=1)
|
|
54
|
+
nan_mask = cp.asarray(nan_mask)
|
|
55
|
+
|
|
56
|
+
# Check for zero signals
|
|
57
|
+
s = refined_signals_gpu
|
|
58
|
+
zero_mask = np.all(refined_signals_cpu == 0, axis=1)
|
|
59
|
+
zero_mask = cp.asarray(zero_mask)
|
|
60
|
+
|
|
61
|
+
# Compute s_star
|
|
62
|
+
s_star = O_gpu @ s.T # shape: [timepoints, num_signals]
|
|
63
|
+
|
|
64
|
+
# Normalize s_star to get s_prime
|
|
65
|
+
s_prime = s_star * (cp.sum(s_star ** 2, axis=0) ** (-0.5))
|
|
66
|
+
|
|
67
|
+
# Compute error-term e = (y.T @ s_prime)^2
|
|
68
|
+
e = cp.sum(Y_signals_gpu * s_prime, axis=0) ** 2 #<----------------------------------
|
|
69
|
+
|
|
70
|
+
# Compute yt_RRt_y
|
|
71
|
+
# # yt_RRt_y = cp.sum(Y_signals_gpu * (R_Rt_gpu @ Y_signals_gpu), axis=0)
|
|
72
|
+
yt_R = Y_signals_gpu * (R_Rt_gpu @ Y_signals_gpu)
|
|
73
|
+
yt_RRt_y = cp.sum(yt_R, axis=0)
|
|
74
|
+
|
|
75
|
+
# Compute final numerator and denominator
|
|
76
|
+
num = yty - e - yt_RRt_y
|
|
77
|
+
den = ystarT_ystar
|
|
78
|
+
|
|
79
|
+
# Apply masks for nan/zero
|
|
80
|
+
num = cp.where(nan_mask, 2.0, num)
|
|
81
|
+
num = cp.where(zero_mask & ~nan_mask, 3.0, num)
|
|
82
|
+
den = cp.where(nan_mask | zero_mask, 1.0, den)
|
|
83
|
+
|
|
84
|
+
return num, den
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def format_in_json_format(cls, r2_results, refined_matching_results, refined_signal_timecourses, refined_signals_present = True):
|
|
88
|
+
json_data_results_with_r2 = []
|
|
89
|
+
|
|
90
|
+
# default r2 value
|
|
91
|
+
for i in range((len(refined_matching_results))):
|
|
92
|
+
r2 = float(r2_results[i])
|
|
93
|
+
muX, muY, sigma = refined_matching_results[i]
|
|
94
|
+
if refined_signals_present:
|
|
95
|
+
refined_signal_timecourse = refined_signal_timecourses[i]
|
|
96
|
+
else:
|
|
97
|
+
refined_signal_timecourse = np.array([None])
|
|
98
|
+
json_entry = JsonMgr.args2jsonEntry(muX, muY, sigma, r2, refined_signal_timecourse)
|
|
99
|
+
json_data_results_with_r2.append(json_entry)
|
|
100
|
+
|
|
101
|
+
return json_data_results_with_r2
|
|
Binary file
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<!-- XML representation of JSON data -->
|
|
2
|
+
<!--
|
|
3
|
+
"@Author : Siddharth Mittal",
|
|
4
|
+
"@Version : 1.0",
|
|
5
|
+
"@Contact : siddharth.mittal@meduniwien.ac.at",
|
|
6
|
+
"@License : (C)Copyright 2024, Medical University of Vienna"
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
<!-- NOTE for Analysis: For DUMMY/Analsis, set correct Visual field at two positions, one for the <stimulus> and another for <search_space>-->
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
<root>
|
|
13
|
+
<!-- Path information -->
|
|
14
|
+
<path_to_append>.../</path_to_append>
|
|
15
|
+
<refine_fitting enable="True" refinefit_on_gpu="True"/> <!-- Execute refine fitting on GPU if sufficient GPU memory is available -->
|
|
16
|
+
|
|
17
|
+
<!-- Stimulus data -->
|
|
18
|
+
<stimulus>
|
|
19
|
+
<!-- File path for stimulus -->
|
|
20
|
+
<directory>/ceph/mri.meduniwien.ac.at/projects/physics/fmri/data/stimsim24/BIDS/derivatives/prfprepare/analysis-01/sub-001/stimuli</directory>
|
|
21
|
+
<visual_field>9</visual_field> <!-- Visual field Radius, NOTE: Use "10" for simulated data, else "9" -->
|
|
22
|
+
<width>101</width>
|
|
23
|
+
<height>101</height>
|
|
24
|
+
<binarization enable="False" threshold="0"/> <!-- stimulus will be binarized if enabled, all values above threshold will be set to 1 and below to 0 -->
|
|
25
|
+
|
|
26
|
+
<!-- Compute model signals with high-res stimulus then downsample: "num_frames_downsampled" = your fMRI timecourse length, "slice_time_ref" for details see https://www.alivelearn.net/?p=1037 -->
|
|
27
|
+
<high_temporal_resolution enable="false" num_frames_downsampled="240" slice_time_ref="0.5"/>
|
|
28
|
+
</stimulus>
|
|
29
|
+
|
|
30
|
+
<!-- Input Data -->
|
|
31
|
+
<input_datasrc>
|
|
32
|
+
<BIDS enable="True" run_type="individual"> <!-- Set to "True" if the input data is organized in BIDS format, select "individual" or "concatenated" run type -->
|
|
33
|
+
<basepath>/ceph/mri.meduniwien.ac.at/projects/physics/fmri/data/stimsim24/BIDS</basepath>
|
|
34
|
+
<append_to_basepath>derivatives, prfprepare</append_to_basepath> <!-- specify if the "analysis-xx" -->
|
|
35
|
+
<!-- <basepath>D:/results/fmri/generic/</basepath> -->
|
|
36
|
+
|
|
37
|
+
<!-- Directory name for results; backups created with timestamp if overwrite="True" -->
|
|
38
|
+
<results_anaylsis_id overwrite="False">GEMpRF</results_anaylsis_id>
|
|
39
|
+
|
|
40
|
+
<!--
|
|
41
|
+
NOTE: Case sensitive, provide the exact values!!!
|
|
42
|
+
For the analysis, sub, ses, task, run, hemi,
|
|
43
|
+
either provide comma separated values or specify "all" (to go through every available analysis)
|
|
44
|
+
Sample: <analysis>01, 02</analysis> or <analysis>all</analysis>
|
|
45
|
+
-->
|
|
46
|
+
<analysis>01</analysis>
|
|
47
|
+
<sub>001, 002</sub>
|
|
48
|
+
<hemi>all</hemi>
|
|
49
|
+
|
|
50
|
+
<!--INDIVIDUAL Task/stimulus Analysis-->
|
|
51
|
+
<individual>
|
|
52
|
+
<task>bar</task> <!--name of the stimulus, this will be used to find the file in the stimulus directory, ONLY one value is allowed-->
|
|
53
|
+
<ses>001nn</ses> <!-- comma separated values or specify "all" -->
|
|
54
|
+
<run>01, 02</run> <!-- comma separated values or specify "all" -->
|
|
55
|
+
</individual>
|
|
56
|
+
|
|
57
|
+
<!--CONCATENATED Analysis-->
|
|
58
|
+
<concatenated>
|
|
59
|
+
<concatenate_item>
|
|
60
|
+
<ses>001</ses> <!-- ONLY one value is allowed-->
|
|
61
|
+
<task>bar</task> <!-- ONLY one value is allowed-->
|
|
62
|
+
<run>02</run> <!-- ONLY one value is allowed-->
|
|
63
|
+
</concatenate_item>
|
|
64
|
+
<concatenate_item>
|
|
65
|
+
<ses>001</ses>
|
|
66
|
+
<task>bar</task>
|
|
67
|
+
<run>04</run>
|
|
68
|
+
</concatenate_item>
|
|
69
|
+
</concatenated>
|
|
70
|
+
</BIDS>
|
|
71
|
+
|
|
72
|
+
<!--OR, make Bids False and specify directly single/multiple filepaths -->
|
|
73
|
+
<fixed_paths>
|
|
74
|
+
<measured_data_filepath> <!-- Measured input data filepaths -->
|
|
75
|
+
<filepath>/ceph/mri.meduniwien.ac.at/projects/physics/fmri/data/tests/gem_generic_test/BIDS/sub-001/ses-3n2/func/sub-001_ses-3n2_task-prf_acq-normal_run-01_bold.nii.gz</filepath>
|
|
76
|
+
<filepath>dummy////sub-001/ses-3n2/func/sub-001_ses-3n2_task-prf_acq-normal_run-01_bold.nii.gz</filepath>
|
|
77
|
+
</measured_data_filepath>
|
|
78
|
+
<results> <!-- Results filepaths realted -->
|
|
79
|
+
<basepath>/ceph/mri.meduniwien.ac.at/projects/physics/fmri/data/tests/gem_generic_test/derivatives/prfanalyze-gem/analysis-01/sub-001/ses-3n2/</basepath> <!-- Base path for results -->
|
|
80
|
+
<custom_filename_postfix>_[gem-new_data-simulated_v1_151x151x8_refine-validation]</custom_filename_postfix> <!-- Custom filename postfix -->
|
|
81
|
+
<prepend_date>True</prepend_date> <!-- Flag to prepend date -->
|
|
82
|
+
</results>
|
|
83
|
+
</fixed_paths>
|
|
84
|
+
</input_datasrc>
|
|
85
|
+
|
|
86
|
+
<!-- Analysis Model -->
|
|
87
|
+
<pRF_model>
|
|
88
|
+
<model>2d_gaussian</model> <!-- 2d_gauss, (DoG, CSS not avaiable at the moment) -->
|
|
89
|
+
</pRF_model>
|
|
90
|
+
|
|
91
|
+
<!-- Measured data section -->
|
|
92
|
+
<measured_data>
|
|
93
|
+
<width>101</width>
|
|
94
|
+
<height>101</height>
|
|
95
|
+
<batches>200</batches>
|
|
96
|
+
</measured_data>
|
|
97
|
+
|
|
98
|
+
<!-- GPU configuration -->
|
|
99
|
+
<gpu>
|
|
100
|
+
<!-- Default GPU -->
|
|
101
|
+
<default_gpu>0</default_gpu>
|
|
102
|
+
<!-- Additional available GPUs -->
|
|
103
|
+
<additional_available_gpus>
|
|
104
|
+
<gpu>1</gpu>
|
|
105
|
+
<gpu>2</gpu>
|
|
106
|
+
<gpu>3</gpu>
|
|
107
|
+
</additional_available_gpus>
|
|
108
|
+
</gpu>
|
|
109
|
+
|
|
110
|
+
<!-- Search space information -->
|
|
111
|
+
<search_space write_debug_info="false">
|
|
112
|
+
<!-- if the user wants to use custom HRF, pRF sizes or Spatial grid, provide the filepath to the H5 file and the keys for each parameter -->
|
|
113
|
+
<optional_analysis_params enable="False" filepath="DIR_PATH/analysis_additional_params.h5">
|
|
114
|
+
<hrf use_from_file="True" key="analysis_params/hrf_values"/>
|
|
115
|
+
<sigmas use_from_file="True" key="analysis_params/sigmas"/>
|
|
116
|
+
<spatial_grid_xy use_from_file="True" key="analysis_params/spatial_grid_xy"/>
|
|
117
|
+
</optional_analysis_params>
|
|
118
|
+
|
|
119
|
+
<!-- if the user wants to generate a rectilinear grid within the GEM-pRF program, specify the default values below. Please NOTE that these values will ONLY be used if their corresponding optional_analysis_params = False -->
|
|
120
|
+
<default_hrf t="(0, 45)" TR="auto" peak_delay="6.16" under_shoot_delay="12.0" peak_disp="0.85" under_disp="0.82" peak_to_undershoot="2.15" normalize="true"/> <!-- SPM parameters, "t" is fed to np.arange(start, stop, step), "step" represents the TR value, set it to a lower value in case of high temporal stimulus. If TR = "auto" then, its value will be read from the stimulus file -->
|
|
121
|
+
<default_spatial_grid visual_field_radius="13.5" num_horizontal_prfs="151" num_vertical_prfs="151"/>
|
|
122
|
+
<default_sigmas num_sigmas="16" min_sigma="0.5" max_sigma="5"/>
|
|
123
|
+
</search_space>
|
|
124
|
+
</root>
|