Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0c88ccb
make instruction to update code clearer
mathrip May 30, 2025
faa1907
Fix subject_id formatting in run_hippunfold_parallel
ckronlage Oct 3, 2025
fda1e1c
Add checks before deleting intermediate files in run_hippunfold_parallel
ckronlage Oct 15, 2025
1c7df31
Merge branch 'main' of https://github.com/MELDProject/AID-HS into v1.0.2
mathrip Dec 12, 2025
df2eff3
Reorient images to RAS for report plots
Jan 21, 2026
41758e6
Use tempfile temporary plot files instead of tmp.png in workdir (may …
Jan 21, 2026
6ace7eb
Remove wrong axis flip and fix origin='lower' in plot_segmentations_s…
Jan 21, 2026
1086fa6
Apply fixes for handling of non-RAS inputs also to other plot_segment…
Jan 21, 2026
f3ec936
add test aidhs license available
mathrip Apr 16, 2026
5b24a96
update documentation with registration file and aidhs license
mathrip Apr 16, 2026
ad4916a
add non commercial license
mathrip Apr 16, 2026
b8c5346
Fix RAS orientation in hippocampus segmentation plot. Integrate PR #1…
mathrip Apr 21, 2026
c82e1b1
enable passing a different demographics file than the default
mathrip Apr 21, 2026
451b7a3
remove group in harmonisation covariate
mathrip Apr 23, 2026
64019b2
update version from v1.0.1 to v1.1.0
mathrip Apr 23, 2026
d1add3f
update guidelines to download aidhs data folder automatically
mathrip Apr 23, 2026
a95ca6e
add scripts to download aidhs data folder automatically
mathrip Apr 23, 2026
cc69464
enable flexible harmo code
mathrip Apr 23, 2026
0c8fdf3
update Dockerfile to use archived repositories for Debian Buster - PR…
mathrip Apr 23, 2026
199ecb4
Fix subject_id formatting in run_hippunfold_parallel - PR 14 from ckr…
mathrip Apr 23, 2026
349a6f9
add aidhs_license environment & keep_data to enable usng on docker
mathrip Apr 23, 2026
5c5447d
update documentation, clarify instructions
mathrip Apr 24, 2026
993d9a1
update instruction to upgrade from v1.0.1 to v1.1.0
mathrip Apr 24, 2026
89fc200
update version docker compose file
mathrip Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ RUN rm /opt/hippunfold_cache/trained_model.3d_fullres.Task102_hcp1200_T2w.nnUNet

# Update OS and install prerequisite
ENV DEBIAN_FRONTEND="noninteractive"
# Use archived repositories for Debian Buster (since it's EOL)
RUN sed -i 's|http://deb.debian.org/debian|http://archive.debian.org/debian|g' /etc/apt/sources.list && \
sed -i 's|http://security.debian.org/debian-security|http://archive.debian.org/debian-security|g' /etc/apt/sources.list && \
sed -i '/buster-updates/d' /etc/apt/sources.list
RUN apt-get --allow-releaseinfo-change update
RUN apt-get install -y python3-pip \
time \
Expand Down Expand Up @@ -38,6 +42,9 @@ RUN cd /app/ && conda run -n base /bin/bash -c "pip install -e ."
# Set permissions for the entrypoint
RUN chmod +x entrypoint.sh

ENV KEEP_DATA_PATH=1
ENV SILENT=1

ENTRYPOINT ["/bin/bash","entrypoint.sh"]


131 changes: 131 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# PolyForm Noncommercial License 1.0.0

<https://polyformproject.org/licenses/noncommercial/1.0.0>

## Acceptance

In order to get any license under these terms, you must agree
to them as both strict obligations and conditions to all
your licenses.

## Copyright License

The licensor grants you a copyright license for the
software to do everything you might do with the software
that would otherwise infringe the licensor's copyright
in it for any permitted purpose. However, you may
only distribute the software according to [Distribution
License](#distribution-license) and make changes or new works
based on the software according to [Changes and New Works
License](#changes-and-new-works-license).

## Distribution License

The licensor grants you an additional copyright license
to distribute copies of the software. Your license
to distribute covers distributing the software with
changes and new works permitted by [Changes and New Works
License](#changes-and-new-works-license).

## Notices

You must ensure that anyone who gets a copy of any part of
the software from you also gets a copy of these terms or the
URL for them above, as well as copies of any plain-text lines
beginning with `Required Notice:` that the licensor provided
with the software. For example:

> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)

## Changes and New Works License

The licensor grants you an additional copyright license to
make changes and new works based on the software for any
permitted purpose.

## Patent License

The licensor grants you a patent license for the software that
covers patent claims the licensor can license, or becomes able
to license, that you would infringe by using the software.

## Noncommercial Purposes

Any noncommercial purpose is a permitted purpose.

## Personal Uses

Personal use for research, experiment, and testing for
the benefit of public knowledge, personal study, private
entertainment, hobby projects, amateur pursuits, or religious
observance, without any anticipated commercial application,
is use for a permitted purpose.

## Noncommercial Organizations

Use by any charitable organization, educational institution,
public research organization, public safety or health
organization, environmental protection organization,
or government institution is use for a permitted purpose
regardless of the source of funding or obligations resulting
from the funding.

## Fair Use

You may have "fair use" rights for the software under the
law. These terms do not limit them.

## No Other Rights

These terms do not allow you to sublicense or transfer any of
your licenses to anyone else, or prevent the licensor from
granting licenses to anyone else. These terms do not imply
any other licenses.

## Patent Defense

If you make any written claim that the software infringes or
contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If
your company makes such a claim, your patent license ends
immediately for work on behalf of your company.

## Violations

The first time you are notified in writing that you have
violated any of these terms, or done anything with the software
not covered by your licenses, your licenses can nonetheless
continue if you come into full compliance with these terms,
and take practical steps to correct past violations, within
32 days of receiving notice. Otherwise, all your licenses
end immediately.

## No Liability

***As far as the law allows, the software comes as is, without
any warranty or condition, and the licensor will not be liable
to you for any damages arising out of these terms or the use
or nature of the software, under any kind of legal claim.***

## Definitions

The **licensor** is the individual or entity offering these
terms, and the **software** is the software the licensor makes
available under these terms.

**You** refers to the individual or entity agreeing to these
terms.

**Your company** is any legal entity, sole proprietorship,
or other kind of organization that you work for, plus all
organizations that have control over, are under the control of,
or are under common control with that organization. **Control**
means ownership of substantially all the assets of an entity,
or the power to direct its management and policies by vote,
contract, or otherwise. Control can be direct or indirect.

**Your licenses** are all the licenses granted to you for the
software under these terms.

**Use** means anything you do with the software requiring one
of your licenses.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ Note:
- You will need the following demographic information (age at scan & sex) to run AID-HS on your patient's T1 MRI scan.
- AID-HS has been developed on T1w scans acquired at 3T. It has not yet been thoroughly evaluated on 1.5T and 7T data

**<span style="color: red;">SIGN UP TO THE AID-HS MAILING LIST</span>**:
We request that all AID-HS users sign up to the mailing list. If you are using AID-HS, please send an email to `meld.study@gmail.com` with the subject 'Request to be added to the AID-HS mailing list' and provide use with your name and institute. This will ensure that we can update you about bug fixs and new releases.

**<span style="color: red;">EXISTING USERS: PLEASE UPDATE TO VERSION V1.0.1</span>**:
We have released AID-HS V1.0.1 which fixes a couple of issues found by users. For more information about the release please see [AID-HS V1.0.1](https://github.com/MELDProject/AID-HS/releases/tag/v1.0.1). To update your code please follow the guidelines [Updating AID-HS to V1.0.1](https://aid-hs.readthedocs.io/en/latest/FAQs.html#Updating-AID-HS-to-V1.0.1) from our FAQ.

**<span style="color: red;">REGISTER TO GET YOUR AID-HS LICENSE</span>**:
We request that all AID-HS users fill the [AID-HS registration form](https://docs.google.com/forms/d/e/1FAIpQLSdPbtraBZ2s0HD1W8qtF11wr_fYVTWZjraED03Rtl2ZjxeRMA/viewform?usp=header). Following registration you will received a license file. This file will be needed for use of all future AID-HS versions v1.1.0 and above. Your email address will be added to the AID-HS mailing list. This will ensure that we can update you about bugs fix and new releases.

Pipeline overview:\
<img src="https://raw.githubusercontent.com//MELDProject/AID-HS/main/docs/images/overview_pipeline.jpg " height="500" />
Expand All @@ -36,6 +32,7 @@ You can install and use the AID-HS pipeline with :
- [**native installation**](https://aid-hs.readthedocs.io/en/latest/install_native.html): Not supported

**YouTube tutorial available for the [docker and singularity installation](https://www.youtube.com/watch?v=RRAET7r05ys&t=11s&ab_channel=MELDproject)**
Note: for installation, please follow the online guidelines on github which are up to date compare to the videos

**FAQs**
If you have a question or if you are running into issues at any stage (installation/use/interpretation), have a look at our [FAQs](https://aid-hs.readthedocs.io/en/latest/FAQs.html) page as we may have already have a solution.
Expand All @@ -56,7 +53,7 @@ Once installed you will be able to use the AID-HS pipeline on your data followin
Features extracted from MRI scans from different MRI scanners have systematic differences between them. To remove scanner related biases we recommend harmonising your MRI data to the MRI data that was used in the AID-HS manuscript. This harmonisation is required for each MRI scanner / T1 sequence you are using.

Notes:
- This step needs to be run only once, and requires data from at least 20 subjects acquired on the same scanner with the same T1 sequence and demographic information (e.g age and sex). See [harmonisation instructions](https://aid-hs.readthedocs.io/en/latest/harmonisation.html) for more details.
- This step needs to be run only once, and requires data from at least 20 controls acquired on the same scanner with the same T1 sequence and demographic information (e.g age and sex). See [harmonisation instructions](https://aid-hs.readthedocs.io/en/latest/harmonisation.html) for more details.
- The AID-HS pipeline can also be run without harmonisation with no drop in performances. However, the characterisation of the hippocampal features compared to the normative growth curves will not be interpretable.


Expand All @@ -69,7 +66,10 @@ An overview of the notebooks that we used to create the figures can be found [he

## Contacts

Mathilde Ripart, PhD \
MELD project\
`meld.study@gmail.com`

Mathilde Ripart, PhD \
Research Fellow at UCL Great Ormond Street Institute of Child Health \
`m.ripart@ucl.ac.uk`

Expand All @@ -80,3 +80,5 @@ Research Fellow at UCL Great Ormond Street Institute of Child Health \





2 changes: 1 addition & 1 deletion aidhs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__author__ = __maintainer__ = "Mathilde Ripart"
__email__ = "m.ripart@ucl.ac.uk"
__version__ = "1.0.1"
__version__ = "1.1.0"
2 changes: 1 addition & 1 deletion aidhs/aidhs_cohort_hip.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def get_sites(self):
sites = []
for f in glob.glob(os.path.join(self.data_dir, "AIDHS_*")):
if os.path.isdir(f):
sites.append(f.split("_")[-1])
sites.append(f.split("AIDHS_")[-1])
return sites

@contextmanager
Expand Down
15 changes: 6 additions & 9 deletions aidhs/data_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ def load_covars(self, subject_ids=None, demographic_file=DEMOGRAPHIC_FEATURES_FI
covars = pd.DataFrame()
ages = []
sex = []
group = []
sites_scanners = []
for subject in subject_ids:
subj = AidhsSubject(subject, cohort=self.cohort)
Expand All @@ -215,12 +214,10 @@ def load_covars(self, subject_ids=None, demographic_file=DEMOGRAPHIC_FEATURES_FI
sex.append(s)
else:
print(f'ERROR: There is an issue with the coded sex of subject {subject}')
group.append(subj.is_patient)
sites_scanners.append(subj.site_code) # just site code now

covars["ages"] = ages
covars["sex"] = sex
covars["group"] = group
covars["site_scanner"] = sites_scanners
covars["ID"] = subject_ids

Expand Down Expand Up @@ -497,7 +494,7 @@ def combat_whole_cohort(self, feature_name, outliers_file=None, combat_params_fi
print(f"INFO: exclude subjects {np.array(self.subject_ids)[~combat_subject_include]}")
if precombat_features:
precombat_features = np.array(precombat_features)
# load in covariates - age, sex, group, site and scanner unless provided
# load in covariates - age, sex, site and scanner unless provided
covars = self.covars[combat_subject_include].copy()
# check for nan
index_nan = pd.isnull(covars).any(1).to_numpy().nonzero()[0]
Expand All @@ -518,7 +515,7 @@ def combat_whole_cohort(self, feature_name, outliers_file=None, combat_params_fi
precombat_features.T,
covars,
batch_col="site_scanner",
categorical_cols=["sex", "group"],
categorical_cols=["sex"],
continuous_cols="ages",
)
#
Expand Down Expand Up @@ -579,7 +576,7 @@ def get_combat_new_site_parameters(self,feature, demographic_file,):
if len(np.array(listids)[np.array(combat_subject_include)])==0:
print(f'Cannot compute harmonisation for {feature} because no subject found with this feature')
return
# load in covariates - age, sex, group, site and scanner unless provided
# load in covariates - age, sex, site and scanner unless provided
new_site_covars = self.load_covars(subject_ids=np.array(listids)[np.array(combat_subject_include)], demographic_file=demographic_file).copy()
#check site_scanner codes are the same for all subjects
if len(new_site_covars['site_scanner'].unique())==1:
Expand All @@ -595,7 +592,7 @@ def get_combat_new_site_parameters(self,feature, demographic_file,):
new_site_data = np.array(precombat_features).T
dc.distributedCombat_site(new_site_data,
bat,
new_site_covars[['ages','sex','group']],
new_site_covars[['ages','sex']],
file=os.path.join(site_combat_path,f"{site_code}_{feature}_summary.pickle"),
ref_batch = 'H0',
robust=True,)
Expand All @@ -606,12 +603,12 @@ def get_combat_new_site_parameters(self,feature, demographic_file,):
)
# third, use variance estimates from full AIDHS cohort
dc_out['var_pooled'] = pd.read_pickle(os.path.join(aidhs_combat_path,f'combat_{feature}_var.pickle')).ravel()
for c in ['ages','sex','group']:
for c in ['ages','sex']:
new_site_covars[c]=new_site_covars[c].astype(np.float64)
print('step3')
pickle_file = os.path.join(site_combat_path,f"{site_code}_{feature}_harmonisation_params_test.pickle")
_=dc.distributedCombat_site(
pd.DataFrame(new_site_data), bat, new_site_covars[['ages','sex','group']],
pd.DataFrame(new_site_data), bat, new_site_covars[['ages','sex']],
file=pickle_file,
central_out=dc_out,
ref_batch = 'H0',
Expand Down
40 changes: 40 additions & 0 deletions aidhs/download_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import urllib.request
import os
import numpy as np
from aidhs.paths import DATA_PATH
import sys
import shutil
import tempfile

def _fetch_url(url, fname):
def dlProgress(count, blockSize, totalSize):
percent = int(count*blockSize*100/totalSize)
if not "SILENT" in os.environ:
sys.stdout.write("\r" + url + "...%d%%" % percent)
sys.stdout.flush()
return urllib.request.urlretrieve(url, fname, reporthook=dlProgress)


def download_aidhs_data(aidhs_data_path=DATA_PATH):
"""
download AID-HS data from GitHub release: model, parameters and test data
"""
url = "https://github.com/MELDProject/AID-HS/releases/download/aidhs_data/aidhs_data.zip"
with tempfile.TemporaryDirectory() as tmpdirname:
# download to tmpdir
_fetch_url(url, os.path.join(tmpdirname, "aidhs_data_folder.zip"))
# unpack
shutil.unpack_archive(os.path.join(tmpdirname, "aidhs_data_folder.zip"), aidhs_data_path)
print(f"\ndownloaded AID-HS data to {aidhs_data_path}")

def check_data(force_download=False):
for folder in ['input','output','models','params']:
exit = False
if os.path.exists(os.path.join(DATA_PATH, folder)):
print(f'The folder {folder} already exists at {DATA_PATH}.')
exit = True
if force_download:
print('Data to download already (partially) exists. \nData will be overwritten.')
if exit and (force_download==False):
print('Data to download already (partially) exists. \nDownload aborted. Please delete folders or provide a new path.')
sys.exit()
2 changes: 1 addition & 1 deletion aidhs/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@


# paths to important data files - relative to BASE_PATH
DEMOGRAPHIC_FEATURES_FILE = os.path.join(DATA_PATH, "demographics_file.csv")
DEMOGRAPHIC_FEATURES_FILE = f"/tmp/demographics_file_{os.getpid()}.csv"

# params file
CLIPPING_PARAMS_FILE='clipping_parameters_sigma.json'
Expand Down
31 changes: 31 additions & 0 deletions aidhs/test/test_aidhs_license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import os
import sys
import re
from pathlib import Path

def test_license():

# Get the meld license variable
aidhs_license_file = os.getenv("AIDHS_LICENSE", None)

if aidhs_license_file is None:
print('ERROR: Could not find a AIDHS_LICENSE environment variable. Please ensure you have exported the AIDHS_LICENSE environment following the AID-HS installation guidelines')
sys.exit()
if not os.path.isfile(aidhs_license_file):
print(f'ERROR: The file {aidhs_license_file} does not exist.\nPlease ensure you got the meld license file by filling the registration form provided in the AID-HS installation guidelines and provided the right path to the file')
sys.exit()

# check that the license is correct
text = Path(aidhs_license_file).read_text()
m = re.search(r"License\s*ID[:\s]*([0-9]+)", text, re.IGNORECASE)
if m:
license_id = m.group(1)
if not len(license_id) == 6:
print("ERROR: The license ID provided does not seem correct.\nPlease ensure you got the correct meld license file by filling the registration form provided in the AID-HS installation guidelines and provided the right path to the file")
sys.exit()
else:
print(f"ERROR: The license file {aidhs_license_file} does not seem correct.\nPlease ensure you got the correct meld license file by filling the registration form provided in the AID-HS installation guidelines and provided the right path to the file")
sys.exit()

# call the test
test_license()
10 changes: 9 additions & 1 deletion compose.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
services:
aidhs:
image: meldproject/aidhs:latest
image: meldproject/aidhs:v1.1.0
platform: "linux/amd64"
volumes:
- volumes:/data
environment:
- AIDHS_LICENSE=/run/secrets/aidhs_license.txt
secrets:
- aidhs_license.txt
user: $DOCKER_USER
deploy:
resources:
Expand All @@ -12,3 +16,7 @@ services:
- capabilities: [gpu]
count: 0

secrets:
aidhs_license.txt:
file: ./aidhs_license.txt

Loading
Loading