Feature Request
Hi,
I would like to get your thoughts on a small extension to Phantom: keeping explicit per-spin compartment labels, and adding helpers to select spins by those labels. I'm looking for early feedback, this is far from a finished PR proposal. Mostly I'd like to know whether the idea feels useful to anyone but me and whether you think the rough API direction fits in with the rest of KomaMRI.
Why?
I have started to think about this in the context of a larger project to make spin properties a bit more flexible, but then I thought this might be useful for the current simulators as well.
Several phantom constructors already use tissue, material, species, or region labels internally to assign contrast parameters. After construction, that membership is usually lost and downstream code only sees spin-indexed vectors.
Keeping those labels on the phantom could make a few workflows more direct:
- tissue-specific editing of contrast parameters;
- ROI extraction and debugging;
- plotting or summarizing spins by tissue/material;
- defining regional motion or other spin-subset operations;
- preserving documented species/pool metadata from imported phantom formats.
Rough Model
The idea is to add static per-spin compartment labels to Phantom.
Compartments are discrete labels only. They do not define contrast values, motion, or simulation behavior. A label identifies membership in a tissue, material, species, region, or pool such as :GM, :WM, :fat, :blood, or :myocardium. For now, I would keep this simple: exactly one compartment label per spin.
When no labels are provided, existing behavior is preserved. We should probably assigning all spins to a default compartment in that case, tentatively :default.
My current thought is to normalize labels internally to Symbols, while accepting both Symbol and AbstractString at public boundaries. For built-in phantoms, I would reuse labels already present in source tables or masks. I think a global KomaMRI label ontology is out-of-scope, at least for now.
Fit With Existing Code
Labels should live on Phantom, since they are spin-aligned sample metadata. They would follow the usual phantom operations:
obj[p] and @view obj[p];
copy;
- equality;
obj1 + obj2;
- precision conversion without numeric conversion of labels;
- no transfer to GPU memory unless future simulation methods consume it;
.phantom file read/write, with old files defaulting to :default.
Current GPU simulation kernels consume numeric spin fields and motion, not compartment labels. If labels are needed to choose a spin subset, that selection should be resolved before backend transfer. We could keep the field present but treat it as a non-transferred leaf to avoid surprising manual gpu(obj) users while avoiding unnecessary GPU memory use.
How to perform spin selection
Existing SpinSpan, AllSpins, and SpinRange would remain unchanged. They are already-resolved index selectors: once constructed, they contain the spin indices or index range to use.
A compartment label such as :GM is different because it is unresolved without a specific phantom’s compartment metadata. To use the compartment labels to select a subset of spins I am leaning toward explicit helpers, because they make the label-to-index resolution visible:
idx = spin_indices(obj, :GM)
obj_gm = obj[idx]
sel = spin_selector(obj, :GM)
motion = translate(..., sel)
spin_indices returns concrete indices and is useful immediately, including for irregular tissue masks.
spin_selector could return existing AbstractSpinSpan values where the selection is exactly representable, for example AllSpins() or SpinRange. Irregular selections probably need a future arbitrary-index span type. I think that part would need more discussion before coming up with an API.
Overloading indexing may be a bit too invasive in adding a new meaning for the indexing operation and it couldn't be used for motion. So I'd avoid:
Possible PR Split
If this seems worth pursuing, I imagine splitting it into small PRs:
- Add compartment storage to
Phantom, preserve all existing constructors and operations, and persist labels in .phantom files.
- Add
spin_indices and possibly a limited spin_selector for selections representable by existing span types.
- Populate compartments in built-in phantoms and external readers where labels are already documented or implicit and unambiguous.
Questions
The obvious one is: Do you think compartments and per-compartment selection would be a useful addition to KomaMRI? I have briefly checked existing feature requests and have not found anything.
Do you see anything wrong with the direction I took in thinking about this? Any obvious design flaws?
And then there are the technicalities:
- Did I forget any phantom operations we need to handle?
- Do you think symbols are a good fit to store labels internally while accepting strings at API and file-I/O boundaries?
- Should the first PR include only
spin_indices, or also a limited spin_selector? Or do you prefer a larger PR once everything is in?
- Is a future arbitrary-index
AbstractSpinSpan desirable for irregular compartment selections, especially for motion APIs?
- Does treating compartments as CPU-side leaf metadata during GPU transfer match expectations for
gpu(obj)?
- What are the requirements for backwards compatibility of the
.phantom files? Would this require a version bump on KomaMRIFiles?
Feature Request
Hi,
I would like to get your thoughts on a small extension to
Phantom: keeping explicit per-spin compartment labels, and adding helpers to select spins by those labels. I'm looking for early feedback, this is far from a finished PR proposal. Mostly I'd like to know whether the idea feels useful to anyone but me and whether you think the rough API direction fits in with the rest of KomaMRI.Why?
I have started to think about this in the context of a larger project to make spin properties a bit more flexible, but then I thought this might be useful for the current simulators as well.
Several phantom constructors already use tissue, material, species, or region labels internally to assign contrast parameters. After construction, that membership is usually lost and downstream code only sees spin-indexed vectors.
Keeping those labels on the phantom could make a few workflows more direct:
Rough Model
The idea is to add static per-spin compartment labels to
Phantom.Compartments are discrete labels only. They do not define contrast values, motion, or simulation behavior. A label identifies membership in a tissue, material, species, region, or pool such as
:GM,:WM,:fat,:blood, or:myocardium. For now, I would keep this simple: exactly one compartment label per spin.When no labels are provided, existing behavior is preserved. We should probably assigning all spins to a default compartment in that case, tentatively
:default.My current thought is to normalize labels internally to
Symbols, while accepting bothSymbolandAbstractStringat public boundaries. For built-in phantoms, I would reuse labels already present in source tables or masks. I think a global KomaMRI label ontology is out-of-scope, at least for now.Fit With Existing Code
Labels should live on
Phantom, since they are spin-aligned sample metadata. They would follow the usual phantom operations:obj[p]and@view obj[p];copy;obj1 + obj2;.phantomfile read/write, with old files defaulting to:default.Current GPU simulation kernels consume numeric spin fields and motion, not compartment labels. If labels are needed to choose a spin subset, that selection should be resolved before backend transfer. We could keep the field present but treat it as a non-transferred leaf to avoid surprising manual
gpu(obj)users while avoiding unnecessary GPU memory use.How to perform spin selection
Existing
SpinSpan,AllSpins, andSpinRangewould remain unchanged. They are already-resolved index selectors: once constructed, they contain the spin indices or index range to use.A compartment label such as
:GMis different because it is unresolved without a specific phantom’s compartment metadata. To use the compartment labels to select a subset of spins I am leaning toward explicit helpers, because they make the label-to-index resolution visible:spin_indicesreturns concrete indices and is useful immediately, including for irregular tissue masks.spin_selectorcould return existingAbstractSpinSpanvalues where the selection is exactly representable, for exampleAllSpins()orSpinRange. Irregular selections probably need a future arbitrary-index span type. I think that part would need more discussion before coming up with an API.Overloading indexing may be a bit too invasive in adding a new meaning for the indexing operation and it couldn't be used for motion. So I'd avoid:
Possible PR Split
If this seems worth pursuing, I imagine splitting it into small PRs:
Phantom, preserve all existing constructors and operations, and persist labels in.phantomfiles.spin_indicesand possibly a limitedspin_selectorfor selections representable by existing span types.Questions
The obvious one is: Do you think compartments and per-compartment selection would be a useful addition to KomaMRI? I have briefly checked existing feature requests and have not found anything.
Do you see anything wrong with the direction I took in thinking about this? Any obvious design flaws?
And then there are the technicalities:
spin_indices, or also a limitedspin_selector? Or do you prefer a larger PR once everything is in?AbstractSpinSpandesirable for irregular compartment selections, especially for motion APIs?gpu(obj)?.phantomfiles? Would this require a version bump on KomaMRIFiles?