Skip to content

Commit

Permalink
Merge pull request #167 from dvm-shlee/main
Browse files Browse the repository at this point in the history
[refactor] brkraw api and update for future version
  • Loading branch information
dvm-shlee authored Apr 30, 2024
2 parents b4424a3 + 9f4120b commit f5f1534
Show file tree
Hide file tree
Showing 39 changed files with 656 additions and 500 deletions.
46 changes: 33 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
# Contributing
# Contributing to BrkRaw

When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change.
Thank you for your interest in contributing to BrkRaw! Whether you're tackling a bug, adding a new feature, or improving our documentation, every contribution is appreciated. This guide will help you get started with your contributions in the most effective way.

Please note we have a code of conduct, please follow it in all your interactions with the project.
## Ways to Contribute

## Pull Request Process
### Reporting Issues

1. Ensure any install or build dependencies are removed before the end of the layer when doing a
build.
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Increase the version numbers in any examples files and the README.md to the new version that this
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you.
If you encounter a bug, have a suggestion, or want to make a feature request, please use the Issues section. Include as much detail as possible and label your issue appropriately.

### Pull Requests

We welcome pull requests with open arms! Here’s how you can make one:

- **Code Changes**: If you are updating the BrkRaw codebase, perhaps due to a ParaVision compatibility issue or to suggest a new standard, please make sure your changes are well-documented.
- **New Features**: If you're introducing a new feature, ensure that you include appropriate test scripts in the `tests` directory, following our standard testing workflow. Check our documentation for more details.
- **New Applications**: Contributions that significantly enhance community utility but cannot be integrated via the plugin architecture should be directed to the main BrkRaw package.

Before creating a pull request, ensure that your code complies with the existing code style and that you have tested your changes locally.

### Contributing to Child Repositories

- **[plugin](../brkraw-plugin)**: For new functionalities at the app level, direct your contributions here.
- **[dataset](../brkraw-dataset)**: To add a new dataset that needs to be tested via BrkRaw CI for data conversion consistency and reliability, please contribute here.
- **[tutorial](../brkraw-tutorial)**: For new tutorials, tutorial revisions, or documentation that would help other users, please contribute to this repository.

## Before You Start

Please review the documentation and Q&A to see if your question has already been answered or if the feature has already been discussed. If you’re unsure about adding a feature or making a change, open an issue to discuss it first.

## Contribution Guidelines

- Ensure your contributions are clear and easy to understand.
- Include any necessary tests and documentation updates.
- Adhere to the coding standards and best practices as outlined in our project documentation.

We look forward to your contributions and are excited to see what you come up with!
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ clean:
rm -rf tests/tutorials

tests/tutorials:
git clone https://github.com/BrkRaw/tutorials.git tests/tutorials
git clone https://github.com/BrkRaw/brkraw-tutorial.git tests/tutorials

tests/tutorials/SampleData/20190724_114946_BRKRAW_1_1: tests/tutorials
unzip -uq tests/tutorials/SampleData/20190724_114946_BRKRAW_1_1.zip -d tests/tutorials/SampleData/
Expand Down
4 changes: 2 additions & 2 deletions brkraw/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .brkobj import StudyObj
from .data import Study
from ..config import ConfigManager

__all__ = [StudyObj, ConfigManager]
__all__ = ['Study', 'ConfigManager']
2 changes: 1 addition & 1 deletion brkraw/api/analyzer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from .affine import AffineAnalyzer
from .dataarray import DataArrayAnalyzer

__all__ = [BaseAnalyzer, ScanInfoAnalyzer, AffineAnalyzer, DataArrayAnalyzer]
__all__ = ['BaseAnalyzer', 'ScanInfoAnalyzer', 'AffineAnalyzer', 'DataArrayAnalyzer']
2 changes: 1 addition & 1 deletion brkraw/api/analyzer/affine.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from copy import copy
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from ..brkobj.scan import ScanInfo
from ..data.scan import ScanInfo


SLICEORIENT = {
Expand Down
2 changes: 1 addition & 1 deletion brkraw/api/analyzer/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class BaseAnalyzer:
def vars(self):
def to_dict(self):
return self.__dict__
3 changes: 2 additions & 1 deletion brkraw/api/analyzer/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from copy import copy
from typing import TYPE_CHECKING, Union
if TYPE_CHECKING:
from ..brkobj import ScanInfo
from ..data import ScanInfo
from io import BufferedReader
from zipfile import ZipExtFile

Expand Down Expand Up @@ -33,3 +33,4 @@ def _calc_array_shape(self, infoobj: 'ScanInfo'):
def get_dataarray(self):
self.buffer.seek(0)
return np.frombuffer(self.buffer.read(), self.dtype).reshape(self.shape, order='F')

9 changes: 8 additions & 1 deletion brkraw/api/analyzer/scaninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,15 @@ def _set_pars(self, pvobj: Union['PvScan', 'PvReco', 'PvFiles'], reco_id: Option
except AttributeError:
vals = OrderedDict()
setattr(self, p, vals)
try:
fid_buffer = pvobj.get_fid()
except (FileNotFoundError, AttributeError):
fid_buffer = None
setattr(self, 'fid_buffer', fid_buffer)

try:
visu_pars = pvobj.get_visu_pars(reco_id)
except FileNotFoundError:
except (FileNotFoundError, AttributeError):
visu_pars = OrderedDict()
setattr(self, 'visu_pars', visu_pars)

Expand All @@ -48,6 +54,7 @@ def _parse_info(self):
self.info_image = helper.Image(self).get_info()
self.info_slicepack = helper.SlicePack(self).get_info()
self.info_cycle = helper.Cycle(self).get_info()
self.info_diffusion = helper.Diffusion(self).get_info()
if self.info_image['dim'] > 1:
self.info_orientation = helper.Orientation(self).get_info()

Expand Down
4 changes: 0 additions & 4 deletions brkraw/api/brkobj/__init__.py

This file was deleted.

77 changes: 0 additions & 77 deletions brkraw/api/brkobj/scan.py

This file was deleted.

4 changes: 4 additions & 0 deletions brkraw/api/data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .study import Study
from .scan import Scan, ScanInfo

__all__ = ['Study', 'Scan', 'ScanInfo']
92 changes: 92 additions & 0 deletions brkraw/api/data/scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from __future__ import annotations
from typing import Optional, Union
import ctypes
from ..pvobj import PvScan, PvReco, PvFiles
from ..pvobj.base import BaseBufferHandler
from ..analyzer import ScanInfoAnalyzer, AffineAnalyzer, DataArrayAnalyzer, BaseAnalyzer


class ScanInfo(BaseAnalyzer):
def __init__(self):
self.warns = []

@property
def num_warns(self):
return len(self.warns)


class Scan(BaseBufferHandler):
"""The Scan class design to interface with analyzer,
Args:
pvobj (_type_): _description_
"""
def __init__(self, pvobj: Union['PvScan', 'PvReco', 'PvFiles'], reco_id: Optional[int] = None,
study_address: Optional[int] = None, debug: bool=False):
self.reco_id = reco_id
self._study_address = study_address
self._pvobj_address = id(pvobj)
self.is_debug = debug
self.set_scaninfo()

def retrieve_pvobj(self):
if self._pvobj_address:
return ctypes.cast(self._pvobj_address, ctypes.py_object).value

def retrieve_study(self):
if self._study_address:
return ctypes.cast(self._study_address, ctypes.py_object).value

def set_scaninfo(self, reco_id:Optional[int] = None):
reco_id = reco_id or self.reco_id
self.info = self.get_scaninfo(reco_id)

def get_scaninfo(self, reco_id:Optional[int] = None, get_analyzer:bool = False):
infoobj = ScanInfo()
pvobj = self.retrieve_pvobj()
analysed = ScanInfoAnalyzer(pvobj, reco_id, self.is_debug)

if get_analyzer:
return analysed
for attr_name in dir(analysed):
if 'info_' in attr_name:
attr_vals = getattr(analysed, attr_name)
if warns:= attr_vals.pop('warns', None):
infoobj.warns.extend(warns)
setattr(infoobj, attr_name.replace('info_', ''), attr_vals)
return infoobj

def get_affine_analyzer(self, reco_id:Optional[int] = None):
if reco_id:
info = self.get_scaninfo(reco_id)
else:
info = self.info if hasattr(self, 'info') else self.get_scaninfo(self.reco_id)
return AffineAnalyzer(info)

def get_datarray_analyzer(self, reco_id: Optional[int] = None):
reco_id = reco_id or self.reco_id
pvobj = self.retrieve_pvobj()
fileobj = pvobj.get_2dseq(reco_id=reco_id)
self._buffers.append
info = self.info if hasattr(self, 'info') else self.get_scaninfo(reco_id)
return DataArrayAnalyzer(info, fileobj)

@property
def avail(self):
return self.pvobj.avail

@property
def pvobj(self):
return self.retrieve_pvobj()

@property
def about_scan(self):
return self.info.to_dict()

@property
def about_affine(self):
return self.get_affine_analyzer().to_dict()

@property
def about_dataarray(self):
return self.get_datarray_analyzer().to_dict()
25 changes: 13 additions & 12 deletions brkraw/api/brkobj/study.py → brkraw/api/data/study.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from __future__ import annotations
from typing import Dict
from ..pvobj import PvDataset
from .scan import ScanObj
from .scan import Scan
from pathlib import Path

class StudyObj(PvDataset):
def __init__(self, path):
class Study(PvDataset):
def __init__(self, path: Path):
super().__init__(path)
self._parse_header()

Expand All @@ -13,8 +13,8 @@ def get_scan(self, scan_id, reco_id=None, debug=False):
Get a scan object by scan ID.
"""
pvscan = super().get_scan(scan_id)
return ScanObj(pvscan=pvscan, reco_id=reco_id,
loader_address=id(self), debug=debug)
return Scan(pvobj=pvscan, reco_id=reco_id,
study_address=id(self), debug=debug)

def _parse_header(self):
if not self.contents or 'subject' not in self.contents['files']:
Expand All @@ -30,16 +30,17 @@ def _parse_header(self):
def avail(self):
return super().avail

@property
@property #TODO
def info(self):
"""output all analyzed information"""
info = {'header': None,
'scans': {}}
if header := self.header:
info['header'] = header
for scan_id in self.avail:
info['scans'][scan_id] = {}
scanobj = self.get_scan(scan_id)
for reco_id in scanobj.avail:
info['scans'][scan_id][reco_id] = scanobj.get_info(reco_id).vars()
# for scan_id in self.avail:
# scanobj = self.get_scan(scan_id)
# info['scans'][scan_id] = {'protocol_name': scanobj.info.protocol['protocol_name'],
# 'recos': {}}
# for reco_id in scanobj.avail:
# info['scans'][scan_id]['recos'][reco_id] = scanobj.get_info(reco_id).frame_group
return info
6 changes: 4 additions & 2 deletions brkraw/api/helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from .cycle import Cycle
from .orientation import Orientation, to_matvec, from_matvec, rotate_affine
from .fid import FID
from .diffusion import Diffusion

__all__ = [Protocol, FID, FrameGroup, DataArray, Image, SlicePack, Cycle, Orientation,
to_matvec, from_matvec, rotate_affine]
__all__ = ['Protocol', 'FID', 'FrameGroup', 'DataArray',
'Image', 'SlicePack', 'Cycle', 'Orientation', 'Diffusion',
'to_matvec', 'from_matvec', 'rotate_affine']
1 change: 0 additions & 1 deletion brkraw/api/helper/cycle.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations
import re
import numpy as np
from typing import TYPE_CHECKING
from .base import BaseHelper
from .frame_group import FrameGroup
Expand Down
Loading

0 comments on commit f5f1534

Please sign in to comment.