Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cms giwaxs support version 1 #100

Merged
merged 127 commits into from
May 6, 2024
Merged
Changes from 1 commit
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
e50136b
create initial CMS files
andrewjlevin Jul 5, 2023
ab094c2
add CMSGIWAXSLoader to loader.py
andrewjlevin Jul 5, 2023
2260022
first attempt at loadSingleImage
andrewjlevin Jul 5, 2023
8d7847e
add loadMd method
andrewjlevin Jul 6, 2023
c3b78db
parameter fix
andrewjlevin Jul 6, 2023
d31f1af
wrote loadSeries method
andrewjlevin Jul 6, 2023
02cca42
syntax fix
andrewjlevin Jul 6, 2023
bb2c510
add coordinates & minor tweaks
andrewjlevin Jul 6, 2023
60874b9
syntax
andrewjlevin Jul 6, 2023
a4071cc
syntax
andrewjlevin Jul 6, 2023
9af942e
round exposure time to 1 decimal
andrewjlevin Jul 6, 2023
a2ca96d
change default naming scheme from None to []
andrewjlevin Jul 7, 2023
cf6c619
silence draw.load print statements
andrewjlevin Jul 7, 2023
7bbba85
remove np.flipud and create pg_convert function in GIWAXS.py
andrewjlevin Jul 8, 2023
c60d4d1
add GIWAXS.py to util.py
andrewjlevin Jul 8, 2023
6d944ef
time coordinate shows ending time, included in pg_convert output
andrewjlevin Jul 8, 2023
c968f11
syntax fix
andrewjlevin Jul 8, 2023
d1de032
array shaping fix
andrewjlevin Jul 8, 2023
db57990
array shaping fix
andrewjlevin Jul 8, 2023
84d19b8
added pg_convert_series fxn
andrewjlevin Jul 8, 2023
fd83f08
changed how time dim is handled & added coordinate units
andrewjlevin Jul 8, 2023
4dbd307
fix typo & sortby time
andrewjlevin Jul 8, 2023
2a74072
sortby series number too
andrewjlevin Jul 8, 2023
2e2c81b
syntax
andrewjlevin Jul 8, 2023
2059af8
series loader fix
andrewjlevin Jul 8, 2023
5ce76ed
add time units
andrewjlevin Jul 8, 2023
05951d0
undo time unit
andrewjlevin Jul 8, 2023
a38231e
updated util GIWAXS import sytnax
andrewjlevin Jul 13, 2023
54c4324
undoing previous commit
andrewjlevin Jul 13, 2023
1babde7
minor QoL drawmask tweaks
andrewjlevin Jul 13, 2023
8339e37
fixes on previous commit
andrewjlevin Jul 13, 2023
aba83f7
more adjustments to drawmask
andrewjlevin Jul 13, 2023
ba87343
more drawmask
andrewjlevin Jul 13, 2023
80617e6
fix ui to not swap axes, messes up mask arr
andrewjlevin Jul 13, 2023
52e20be
added option to load iterables into loadSeries
andrewjlevin Jul 14, 2023
62cbee0
syntax fix
andrewjlevin Jul 14, 2023
551d13c
another fix, make for iterables
andrewjlevin Jul 14, 2023
2dc065e
added tqdm progress bar
andrewjlevin Jul 14, 2023
4d90c6f
do not flip masks in pg_convert
andrewjlevin Jul 14, 2023
95e4454
make Transform class for pg functions
andrewjlevin Jul 15, 2023
867836f
add Transform to util
andrewjlevin Jul 15, 2023
de931e3
updated the Transform class method to accept both .edf and .json files
Jul 17, 2023
1de6171
cms-giwaxs-in_situ_processing notebooks
Jul 18, 2023
41b7631
cms-giwaxs-in_situ_processing notebooks take2
Jul 18, 2023
546ce65
adding comments, error handling and delim method variable to loadMd()
kewh5868 Jul 18, 2023
a8f71f8
refactored GIWAXS.py Transform class to include generalized load_mask…
kewh5868 Jul 18, 2023
f306a83
added createSampleDictionary() and selectSampleandSeries() methods to…
kewh5868 Jul 18, 2023
5329278
updating module imports in cmsgiwaxsloader() class to include correct…
kewh5868 Jul 18, 2023
5070201
adding save_as_zarr method to the Transform() object, and adding a Pr…
kewh5868 Jul 18, 2023
1cbff90
update the Process() class to ProcessData(), and removing inheritance…
kewh5868 Jul 18, 2023
41135a8
remove corrections module usage
kewh5868 Jul 18, 2023
de34434
adding error handling for selectsampleandseries and createSampleDicti…
kewh5868 Jul 18, 2023
4735e0f
moving return statement
kewh5868 Jul 18, 2023
629198a
updating selectSampleAndSeries(self) to include quit sequence. updati…
kewh5868 Jul 18, 2023
771a32d
removed "add_time_coord" method as it was broken. only the raw DA con…
andrewjlevin Jul 18, 2023
bf9af0a
Merge branch 'cms-giwaxs-support' of https://github.com/ToneyGroupCU/…
andrewjlevin Jul 18, 2023
a71baff
adding cell on multiple data set loading to the cms-giwaxs_process.ip…
kewh5868 Jul 18, 2023
a38ac73
added tqdm descriptions for loadSeries & pg_convert_series methods
andrewjlevin Jul 18, 2023
324c5c3
added custom energy parameter to Transform
andrewjlevin Jul 20, 2023
13657de
remove FileLoader inheritance of CMSGIWAXSLoader
andrewjlevin Jul 22, 2023
7e3a14f
Merge branch 'usnistgov:main' into cms-giwaxs-support
andrewjlevin Jul 25, 2023
3424894
added new function "single_images_to_dataset" inside GIWAXS.py, added…
andrewjlevin Jul 26, 2023
96659e1
Merge branches 'cms-giwaxs-support' and 'cms-giwaxs-support' of https…
andrewjlevin Jul 26, 2023
d1d3942
add interpolation correction to aforementioned function
andrewjlevin Jul 26, 2023
b9331f4
fix save_zarrs option in aforementioned function
andrewjlevin Jul 26, 2023
66a55f1
minor tweak to single_images_to_dataset function zarr saving lines
andrewjlevin Jul 26, 2023
e401a38
typo fixes
andrewjlevin Jul 26, 2023
efb043c
refined example notebooks & added brief readme.txt to CMS tutorial fo…
Jul 26, 2023
e4f48f9
slight typo fix
andrewjlevin Aug 9, 2023
222b349
Merge branch 'usnistgov:main' into cms-giwaxs-support
andrewjlevin Aug 9, 2023
a1d7189
allow maskPath to be a literal numpy ndarray
andrewjlevin Aug 15, 2023
6553b20
transformer init fix
andrewjlevin Aug 15, 2023
de572d2
Tidy up code in PFGeneralIntegrator
pbeaucage Apr 15, 2024
73b6ef0
Add zarr saving to fileio
pbeaucage Apr 15, 2024
465f1b9
Change sigma output to unified code that copies dims/coords
pbeaucage Apr 15, 2024
4b165b4
Add ponifile loading to PFGE
pbeaucage Apr 15, 2024
3acbe51
Add edf mask loading to PFGE
pbeaucage Apr 15, 2024
9ae38e6
Add missed import
pbeaucage Apr 15, 2024
4d947c2
Rewrite Transform to use PFGeneralIntegrator machinery
pbeaucage Apr 15, 2024
312d7d3
Rename GIWAXS to PGGeneralIntegrator
pbeaucage Apr 15, 2024
cef3f21
loader: raise error if 'files' is not pathlib.Path or iterable
andrewjlevin Apr 15, 2024
d2bfb2a
loader: commit 9 suggestions from code review
andrewjlevin Apr 15, 2024
782b139
Merge pull request #2 from pbeaucage/pr/100
andrewjlevin Apr 15, 2024
d9c22d6
fix indentation error
andrewjlevin Apr 23, 2024
3790a8b
remove Union syntax in saveZarr function (avoid NameError)
andrewjlevin Apr 23, 2024
79c758b
remove legacy giwaxs import in util.py
andrewjlevin Apr 23, 2024
f2ff5cd
small naming/syntax fixes caught in linting/github test runs
andrewjlevin Apr 23, 2024
4cb0aa3
add PGGeneralIntegrator to integrate.py
andrewjlevin Apr 23, 2024
250f77e
fix naming error for loading pyhyper mask
andrewjlevin Apr 23, 2024
b86f46a
remove maskpath argument, so that it only exists in kwargs
andrewjlevin Apr 23, 2024
007566b
pyfai needs ponifile path input to be a string
andrewjlevin Apr 23, 2024
28c1a07
update if statement in ponifile loader
andrewjlevin Apr 23, 2024
d9a7685
add template_xr to ponifile loader for empty masks
andrewjlevin Apr 23, 2024
6bd207c
add filename as attribute if no md scheme is provided. add unused arg…
andrewjlevin Apr 24, 2024
f1341a9
change value comparison to check if img is None in loadFileSeries
andrewjlevin Apr 24, 2024
929b242
add pygix to requirements
andrewjlevin Apr 24, 2024
d681a5b
add file_filter pathlib glob filtering
andrewjlevin Apr 24, 2024
a4c763f
file needs to be a string?
andrewjlevin Apr 24, 2024
fe9d936
updating, file should be a str of just the filename
andrewjlevin Apr 24, 2024
d8257a0
update to how the existing stacking dimension is preserved in integra…
andrewjlevin Apr 24, 2024
7c5f1c0
more syntax rearranging to preserve stacking dimension
andrewjlevin Apr 24, 2024
f07661a
consistenty fix, should let loadFileSeries work without needing a fil…
andrewjlevin Apr 24, 2024
e13219b
update single_images_to_dataset function
andrewjlevin Apr 24, 2024
379ce48
update single_image_to_ds function to update incident angle for each …
andrewjlevin Apr 24, 2024
eb93a0b
Merge remote-tracking branch 'nist/main' into cms-giwaxs-support
andrewjlevin Apr 24, 2024
8f9356a
updated time series processing notebook for new branch update
Apr 25, 2024
05ef956
Update main.yml
andrewjlevin Apr 25, 2024
0384c34
Update main.yml
andrewjlevin Apr 25, 2024
e87aea4
remove filetoload argument from a couple mask loaders, already using …
andrewjlevin Apr 25, 2024
958fe5a
Update requirements.txt; specify version of silx for pygix to work
andrewjlevin Apr 25, 2024
00731f5
update nika mask test
andrewjlevin Apr 25, 2024
b67461a
Merge branch 'cms-giwaxs-support' of https://github.com/ToneyGroupCU/…
andrewjlevin Apr 25, 2024
f714632
logic fix; add single_imgs_to_ds function to a new CMSGIWAXS class in…
andrewjlevin Apr 25, 2024
fc299f3
fix missing tqdm import
andrewjlevin Apr 25, 2024
5bc3e52
rearrange order of functions / methods. add more documentation across…
andrewjlevin Apr 26, 2024
fe57679
updated cms giwaxs tutorials to reflected updated cms-giwaxs-support
Apr 26, 2024
ae3f057
Update requirements.txt: add comment for silx specification
andrewjlevin Apr 26, 2024
66a17d5
add main.yml wgets & test_CMSLoader.py; also CMS Loader init docstr…
andrewjlevin Apr 28, 2024
d6d80ec
cmsgiwaxsloader: tidy imports & switch from PIL to fabio for image lo…
andrewjlevin Apr 30, 2024
05c9650
uncomment cmsloader test lines
andrewjlevin May 1, 2024
c34babc
fix: add naming scheme to test loader and correct attribute dim from…
andrewjlevin May 1, 2024
8b7e6eb
cmsloader: use PIL for tiffs (avoid fabio warning), fabio for anythin…
andrewjlevin May 1, 2024
7907e5f
add optional filename md scheme check before making cmsgiwaxsloaders
May 1, 2024
21c691f
move empty template_xr mask creation to __init__, minor dosctring cha…
andrewjlevin May 2, 2024
740b2cb
remote init empty mask creation, it's already in pygix integrateSingl…
andrewjlevin May 2, 2024
b6818be
fix: add empty mask back to calibrationFromTemplateXRParams
andrewjlevin May 2, 2024
d70681d
update tutorial processing notebooks to not used template_xr for inte…
May 2, 2024
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
Prev Previous commit
Next Next commit
Rewrite Transform to use PFGeneralIntegrator machinery
pbeaucage committed Apr 15, 2024
commit 4d947c2a8046984f13d328b0659b99bbb0896257
484 changes: 113 additions & 371 deletions src/PyHyperScattering/GIWAXS.py
Original file line number Diff line number Diff line change
@@ -10,140 +10,148 @@
import xarray as xr
import numpy as np
import pygix # type: ignore
import fabio # fabio package for .edf imports
import pathlib
from typing import Union, Tuple
from PyHyperScattering.IntegrationUtils import DrawMask
from tqdm.auto import tqdm

class Transform:
""" Class for transforming GIWAXS data into different formats. """
class PGGeneralIntegrator(PFGeneralIntegrator):
"""
Integrator for GIWAXS data based on pygix.
Inherits from PFGeneralIntegrator so as to benefit from its utility methods for mask loading, etc.
"""
def __init__(self,
poniPath: Union[str, pathlib.Path],
maskPath: Union[str, pathlib.Path, np.ndarray],
inplane_config: str = 'q_xy',
energy: float = None):
"""
Attributes:
poniPath (pathlib Path or str): Path to .poni file for converting to q-space
& applying missing wedge correction
maskPath (pathlib Path or str or np.array): Path to the mask file to use
for the conversion, or a numpy array
inplane_config (str): The configuration of the inplane. Default is 'q_xy'.
energy (optional, float): Set energy if default energy in poni file is invalid
inplane_config: str = 'q_xy',
sample_orientation: int = 3,
incident_angle = 0.12,
tilt_angle = 0.0,
output_space = 'recip'
**kwargs):
"""
PyGIX-backed Grazing Incidence Integrator
self.poniPath = pathlib.Path(poniPath)
try:
self.maskPath = pathlib.Path(maskPath)
except TypeError:
self.maskPath = maskPath

self.inplane_config = inplane_config
if energy:
self.energy = energy
self.wavelength = np.round((4.1357e-15*2.99792458e8)/(energy*1000), 13)
else:
self.energy = None
self.wavelength = None

def load_mask(self, da):
"""Load the mask file based on its file type."""
Inputs:
inplane_config (str, default 'q_xy'): The q axis to be considered in-plane.
sample_orientation (int, default 3): the sample orientation relative to the detector. see PyGIX docs.
incident_angle (float, default 0.12): the incident angle, can also be set with .incident_angle = x.xx
tilt_angle (float, default 0): sample tilt angle, can also be set with .tilt_angle = x.xx
output_space (str, 'recip' or 'caked'): whether to produce reciprocal space (q_xy vs q_z, e.g.) data
or 'caked' style data as with PF series integrators (|q| vs chi)
if isinstance(self.maskPath, np.ndarray):
return self.maskPath
See docstring for PFGeneralIntegrator for all geometry kwargs, which work here.
try:
if self.maskPath.suffix == '.json':
draw = DrawMask(da)
draw.load(self.maskPath)
return draw.mask
elif self.maskPath.suffix == '.edf':
return fabio.open(self.maskPath).data
else:
raise ValueError(f"Unsupported file type: {self.maskPath.suffix}")
except Exception as e:
print(f"An error occurred while loading the mask file: {e}")
"""
self.inplane_config = inplane_config
self.sample_orientation = sample_orientation
self.incident_angle = incident_angle
self.tilt_angle = tilt_angle
self.output_space
super().__init__(**kwargs) # all other setup is done by the recreateIntegrator() function and superclass

def pg_convert(self, da):
# def load_mask(self, da): has been superseded by PFGeneralIntegrator's methods

# need to override this to make the PyGIX object
def recreateIntegrator(self):
'''
recreate the integrator, after geometry change
'''
self.integrator = pygix.Transform(dist= self.dist,
poni1 = self.poni1,
poni2 = self.poni2,
rot1 = self.rot1,
rot2 = self.rot2,
rot3 = self.rot3,
pixel1 = self.pixel1,
pixel2 = self.pixel2,
wavelength = self.wavelength,
useqx=True,
sample_orientation = self.sample_orientation,
incident_angle = self.incident_angle,
tilt_angle = self.tilt_angle)


def integrateSingleImage(self, da):
"""
Converts raw GIWAXS detector image to q-space data. Returns two DataArrays, Qz vs Qxy & Q vs Chi
Inputs: Raw GIWAXS DataArray
Outputs: Cartesian & Polar DataArrays
"""

# Initialize pygix transform object
pg = pygix.Transform()
pg.load(str(self.poniPath))
pg.sample_orientation = 3
pg.incident_angle = float(da.incident_angle[2:])
if self.wavelength:
pg.wavelength = self.wavelength

# Load mask
mask = self.load_mask(da)
# Initialize pygix transform object - moved to recreateIntegrator

# the following index stack/unstack code copied from PFGeneralIntegrator
if(img.ndim>2):

img_to_integ = np.squeeze(img.values)
else:
img_to_integ = img.values

if self.mask is None:
warnings.warn('No mask defined. Creating an empty mask with dimensions {img.shape}.',stacklevel=2)
self.mask = np.zeros_like(img).squeeze()
assert np.shape(self.mask)==np.shape(img_to_integ),f'Error! Mask has shape {np.shape(self.mask)} but you are attempting to integrate data with shape {np.shape(img_to_integ)}. Try changing mask orientation or updating mask.'
stacked_axis = list(img.dims)
stacked_axis.remove('pix_x')
stacked_axis.remove('pix_y')
if len(stacked_axis)>0:
assert len(stacked_axis)==1, f"More than one dimension left after removing pix_x and pix_y, I see {stacked_axis}, not sure how to handle"
stacked_axis = stacked_axis[0]
#print(f'looking for {stacked_axis} in {img[0].indexes} (indexes), it has dims {img[0].dims} and looks like {img[0]}')
if(img.__getattr__(stacked_axis).shape[0]>1):
system_to_integ = img[0].indexes[stacked_axis]
warnings.warn(f'There are two images for {img.__getattr__(stacked_axis)}, I am ONLY INTEGRATING THE FIRST. This may cause the labels to be dropped and the result to need manual re-tagging in the index.',stacklevel=2)
else:
system_to_integ = img.indexes[stacked_axis]

else:
stacked_axis = 'image_num'
system_to_integ = [0]

# Cartesian 2D plot transformation
recip_data, qxy, qz = pg.transform_reciprocal(da.data,
if output_space == 'recip':
recip_data, qxy, qz = self.integrator.transform_reciprocal(img_to_integ,
method='bbox',
unit='A',
mask=mask,
correctSolidAngle=True)
mask=self.mask,
correctSolidAngle=self.correctSolidAngle)

recip_da = xr.DataArray(data=recip_data,
dims=['q_z', self.inplane_config],
out_da = xr.DataArray(data=recip_data,
dims=['q_z', self.inplane_config],
coords={
'q_z': ('q_z', qz, {'units': '1/Å'}),
self.inplane_config: (self.inplane_config, qxy, {'units': '1/Å'})
},
attrs=da.attrs)
elif output_space == 'caked':
caked_data, qr, chi = pg.transform_image(img_to_integ,
process='polar',
method = 'bbox',
unit='q_A^-1',
mask=mask,
correctSolidAngle=True)

out_da = xr.DataArray(data=caked_data,
dims=['chi', 'qr'],
coords={
'q_z': ('q_z', qz, {'units': '1/Å'}),
self.inplane_config: (self.inplane_config, qxy, {'units': '1/Å'})
'chi': ('chi', chi, {'units': '°'}),
'qr': ('qr', qr, {'units': '1/Å'})
},
attrs=da.attrs)
out_da.attrs['inplane_config'] = self.inplane_config

# Polar 2D plot transformation
caked_data, qr, chi = pg.transform_image(da.data,
process='polar',
method = 'bbox',
unit='q_A^-1',
mask=mask,
correctSolidAngle=True)

caked_da = xr.DataArray(data=caked_data,
dims=['chi', 'qr'],
coords={
'chi': ('chi', chi, {'units': '°'}),
'qr': ('qr', qr, {'units': '1/Å'})
},
attrs=da.attrs)
caked_da.attrs['inplane_config'] = self.inplane_config
# Preseve any existing dimension if it is in the dataarray, for stacking purposes
if stacked_axis in da.coords:
out_da = out_da.assign_coords({stacked_axis:system_to_integ})
out_da = out_da.expand_dims(dim={stacked_axis: 1})

# Preseve time dimension if it is in the dataarray, for stacking purposes
if 'time' in da.coords:
recip_da = recip_da.assign_coords({'time': float(da.time)})
recip_da = recip_da.expand_dims(dim={'time': 1})
caked_da = caked_da.assign_coords({'time': float(da.time)})
caked_da = caked_da.expand_dims(dim={'time': 1})

return recip_da, caked_da
return out_da

def pg_convert_series(self, da):
"""
Converts raw GIWAXS DataArray to q-space and returns Cartesian & Polar DataArrays
Inputs: Raw GIWAXS DataArray with a time dimension
Outputs: 2 DataArrays in q-space with dimensions (q_z, inplane_config (default is q_xy), time) and (chi, qr, time)
"""
recip_das = []
caked_das = []
for time in tqdm(da.time, desc='Transforming raw GIWAXS time slices'):
da_slice = da.sel(time=float(time))
recip_da_slice, caked_da_slice = self.pg_convert(da=da_slice)
recip_das.append(recip_da_slice)
caked_das.append(caked_da_slice)

recip_da_series = xr.concat(recip_das, 'time')
caked_da_series = xr.concat(caked_das, 'time')

return recip_da_series, caked_da_series
def __str__(self):
return f"PyGIX general integrator wrapper SDD = {self.dist} m, poni1 = {self.poni1} m, poni2 = {self.poni2} m, rot1 = {self.rot1} rad, rot2 = {self.rot2} rad"

def single_images_to_dataset(files, loader, transformer, savePath=None, savename=None):
"""
@@ -204,269 +212,3 @@ def single_images_to_dataset(files, loader, transformer, savePath=None, savename
return raw_DS, recip_DS, caked_DS


# save_as_zarr method from the Transform class, commented (07/25/23)
'''
# # - This needs to be updated appropriately so that it can be called inline. Process(Transform) should be able
# # to import the attribute name of a newly generated .zarr by an active Transform() object instance.
# def save_as_zarr(self, da: xr.DataArray, base_path: Union[str, pathlib.Path], prefix: str, suffix: str, mode: str = 'w'):
# """
# Save the DataArray as a .zarr file in a specific path, with a file name constructed from a prefix and suffix.
# Parameters:
# da (xr.DataArray): The DataArray to be saved.
# base_path (Union[str, pathlib.Path]): The base path to save the .zarr file.
# prefix (str): The prefix to use for the file name.
# suffix (str): The suffix to use for the file name.
# mode (str): The mode to use when saving the file. Default is 'w'.
# """
# ds = da.to_dataset(name='DA')
# file_path = pathlib.Path(base_path).joinpath(f"{prefix}_{suffix}.zarr")
# ds.to_zarr(file_path, mode=mode)
'''

# Keith's ProcessData class, commented out temporarily (07/25/23)
'''
class ProcessData:
def __init__(self,
raw_zarr_file_path: Union[str, pathlib.Path],
pg_transformer: Transform):
"""
Constructor of the ProcessData class.
Parameters:
raw_zarr_file_path (Union[str, pathlib.Path]): The path to the raw .zarr file.
pg_transformer (Transform): An instance of the Transform class for performing the conversion.
"""
self.raw_zarr_file_path = pathlib.Path(raw_zarr_file_path)
self.pg_transformer = pg_transformer
self.raw_da = self.load_zarr(self.raw_zarr_file_path)
self.recip_zarr_file_path, self.caked_zarr_file_path = self.convert_raw_zarr_to_recip_and_caked()
self.recip_da = self.load_zarr(self.recip_zarr_file_path)
self.caked_da = self.load_zarr(self.caked_zarr_file_path)
def load_zarr(self, file_path: Union[str, pathlib.Path]):
"""
Load a .zarr file as an xarray DataArray.
Parameters:
file_path (Union[str, pathlib.Path]): The path to the .zarr file.
Returns:
xr.DataArray: The loaded xarray DataArray.
"""
return xr.open_zarr(str(file_path)).DA
def convert_raw_zarr_to_recip_and_caked(self):
"""
Convert the raw DataArray to reciprocal and caked DataArrays, and save them as .zarr files.
The paths to the new .zarr files are returned.
Returns:
Tuple[pathlib.Path, pathlib.Path]: The paths to the .zarr files for the reciprocal and caked DataArrays.
"""
recip_da, caked_da = self.pg_transformer.pg_convert_series(self.raw_da)
recip_zarr_file_path = self.raw_zarr_file_path.with_name(f"recip_{self.raw_zarr_file_path.stem}.zarr")
recip_da.to_dataset(name='DA').to_zarr(recip_zarr_file_path, mode='w')
caked_zarr_file_path = self.raw_zarr_file_path.with_name(f"caked_{self.raw_zarr_file_path.stem}.zarr")
caked_da.to_dataset(name='DA').to_zarr(caked_zarr_file_path, mode='w')
return recip_zarr_file_path, caked_zarr_file_path
def azimuthal_integration(self, recip_da_series: xr.DataArray, caked_da_series: xr.DataArray, dim: Union[str, Tuple[str]]):
"""
Perform 1D azimuthal integration using boxcuts.
Parameters:
caked_da_series (xr.DataArray): The caked DataArray series.
dim (Union[str, Tuple[str]]): The dimension(s) over which to integrate.
Returns:
Tuple[xr.DataArray, xr.DataArray]: The integrated reciprocated and caked DataArray series.
"""
caked_integrated = caked_da_series.integrate(dim)
return caked_integrated
'''

# -- old Tranform class, refactored: (07/17/23)
'''
class Transform:
def __init__(self, poniPath, maskPath, inplane_config='q_xy'):
self.poniPath = poniPath
self.maskPath = maskPath
self.inplane_config = inplane_config
def pg_convert(self, da):
"""
Converts raw GIWAXS detector image to q-space data. Returns two DataArrays, Qz vs Qxy & Q vs Chi
Inputs: Raw GIWAXS DataArray
Path to .poni file for converting to q-space & applying missing wedge correction
Outputs: Cartesian & Polar DataArrays
"""
# Initialize pygix transform object
pg = pygix.Transform()
pg.load(str(self.poniPath))
pg.sample_orientation = 3
pg.incident_angle = float(da.incident_angle[2:])
# print (self.maskPath.suffix)
if self.maskPath.suffix == '.json':
# Load PyHyper-drawn mask
draw = DrawMask(da) # Assuming 'da' is defined somewhere in your code
draw.load(self.maskPath)
mask = draw.mask
elif self.maskPath.suffix == '.edf':
# Load EDF file using MNE
# mask = mne.io.read_raw_edf(self.maskPath)
mask = fabio.open(self.maskPath).data # load mask file
else:
print(f"Unsupported file type: {self.maskPath.suffix}")
recip_data, qxy, qz = pg.transform_reciprocal(da.data,
method='bbox',
unit='A',
mask=mask,
correctSolidAngle=True)
recip_da = xr.DataArray(data=recip_data,
dims=['q_z', self.inplane_config],
coords={
'q_z': ('q_z', qz, {'units': '1/Å'}),
self.inplane_config: (self.inplane_config, qxy, {'units': '1/Å'})
},
attrs=da.attrs)
caked_data, qr, chi = pg.transform_image(da.data,
process='polar',
method = 'bbox',
unit='q_A^-1',
mask=mask,
correctSolidAngle=True)
caked_da = xr.DataArray(data=caked_data,
dims=['chi', 'qr'],
coords={
'chi': ('chi', chi, {'units': '°'}),
'qr': ('qr', qr, {'units': '1/Å'})
},
attrs=da.attrs)
caked_da.attrs['inplane_config'] = self.inplane_config
if 'time' in da.coords:
recip_da = recip_da.assign_coords({'time': float(da.time)})
recip_da = recip_da.expand_dims(dim={'time': 1})
caked_da = caked_da.assign_coords({'time': float(da.time)})
caked_da = caked_da.expand_dims(dim={'time': 1})
return recip_da, caked_da
def pg_convert_series(self, da):
"""
Converts raw GIWAXS DataArray to q-space and returns Cartesian & Polar DataArrays
Inputs: Raw GIWAXS DataArray with a time dimension
Outputs: 2 DataArrays in q-space with dimensions (q_z, inplane_config (default is q_xy), time) and (chi, qr, time)
"""
recip_das = []
caked_das = []
for time in tqdm(da.time):
da_slice = da.sel(time=float(time))
recip_da_slice, caked_da_slice = self.pg_convert(da=da_slice)
recip_das.append(recip_da_slice)
caked_das.append(caked_da_slice)
recip_da_series = xr.concat(recip_das, 'time')
caked_da_series = xr.concat(caked_das, 'time')
return recip_da_series, caked_da_series
'''

# -- old pg_convert script (07/17/23)
'''
# def pg_convert(da, poniPath, maskPath, inplane_config='q_xy'):
# """
# Converts raw GIWAXS detector image to q-space data. Returns two DataArrays, Qz vs Qxy & Q vs Chi
# Inputs: Raw GIWAXS DataArray
# Path to .poni file for converting to q-space & applying missing wedge correction
# Outputs: Cartesian & Polar DataArrays
# """
# # Initialize pygix transform object
# pg = pygix.Transform()
# pg.load(str(poniPath))
# pg.sample_orientation = 3
# pg.incident_angle = float(da.incident_angle[2:])
# # Load PyHyper-drawn mask
# draw = DrawMask(da)
# draw.load(maskPath)
# mask = draw.mask
# recip_data, qxy, qz = pg.transform_reciprocal(da.data,
# method='bbox',
# unit='A',
# mask=mask,
# correctSolidAngle=True)
# recip_da = xr.DataArray(data=recip_data,
# dims=['q_z', inplane_config],
# coords={
# 'q_z': ('q_z', qz, {'units': '1/Å'}),
# inplane_config: (inplane_config, qxy, {'units': '1/Å'})
# },
# attrs=da.attrs)
# caked_data, qr, chi = pg.transform_image(da.data,
# process='polar',
# method = 'bbox',
# unit='q_A^-1',
# mask=mask,
# correctSolidAngle=True)
# caked_da = xr.DataArray(data=caked_data,
# dims=['chi', 'qr'],
# coords={
# 'chi': ('chi', chi, {'units': '°'}),
# 'qr': ('qr', qr, {'units': '1/Å'})
# },
# attrs=da.attrs)
# caked_da.attrs['inplane_config'] = inplane_config
# if 'time' in da.coords:
# recip_da = recip_da.assign_coords({'time': float(da.time)})
# recip_da = recip_da.expand_dims(dim={'time': 1})
# caked_da = caked_da.assign_coords({'time': float(da.time)})
# caked_da = caked_da.expand_dims(dim={'time': 1})
# return recip_da, caked_da
# def pg_convert_series(da, poniPath, maskPath, inplane_config='q_xy'):
# """
# Converts raw GIWAXS DataArray to q-space and returns Cartesian & Polar DataArrays
# Inputs: Raw GIWAXS DataArray with a time dimension
# Outputs: 2 DataArrays in q-space with dimensions (q_z, inplane_config (default is q_xy), time) and (chi, qr, time)
# """
# recip_das = []
# caked_das = []
# for time in tqdm(da.time):
# da_slice = da.sel(time=float(time))
# recip_da_slice, caked_da_slice = pg_convert(da=da_slice,
# poniPath=poniPath,
# maskPath=maskPath,
# inplane_config=inplane_config)
# recip_das.append(recip_da_slice)
# caked_das.append(caked_da_slice)
# recip_da_series = xr.concat(recip_das, 'time')
# caked_da_series = xr.concat(caked_das, 'time')
# return recip_da_series, caked_da_series
'''