ScatTools 0.0.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.
@@ -0,0 +1,43 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ build:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: '3.12'
22
+ - name: Install dependencies
23
+ run: |
24
+ python -m pip install --upgrade pip
25
+ pip install sphinx sphinx-rtd-theme numpy matplotlib h5py
26
+ - name: Build documentation
27
+ run: |
28
+ make docs
29
+ - name: Upload artifact
30
+ uses: actions/upload-pages-artifact@v3
31
+ with:
32
+ path: docs/_build/html
33
+
34
+ deploy:
35
+ environment:
36
+ name: github-pages
37
+ url: ${{ steps.deployment.outputs.page_url }}
38
+ runs-on: ubuntu-latest
39
+ needs: build
40
+ steps:
41
+ - name: Deploy to GitHub Pages
42
+ id: deployment
43
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,30 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build-and-publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v5
18
+ with:
19
+ python-version: '3.x'
20
+
21
+ - name: Install build dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install build
25
+
26
+ - name: Build package
27
+ run: python -m build
28
+
29
+ - name: Publish package
30
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ dist/
5
+ build/
6
+ docs/_build/
7
+ docs/.doctrees/
8
+ .venv/
9
+ venv/
10
+ *.egg-info/
11
+ .pytest_cache/
12
+ .ruff_cache/
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
@@ -0,0 +1 @@
1
+ ScatTools
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$/../ScatTools" />
5
+ <orderEntry type="jdk" jdkName="Python 3.12 virtualenv at ~/Desktop/Xray" jdkType="Python SDK" />
6
+ <orderEntry type="sourceFolder" forTests="false" />
7
+ </component>
8
+ </module>
@@ -0,0 +1,12 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
5
+ <option name="ignoredIdentifiers">
6
+ <list>
7
+ <option value="lmfit.minimizer.MinimizerResult.params" />
8
+ </list>
9
+ </option>
10
+ </inspection_tool>
11
+ </profile>
12
+ </component>
@@ -0,0 +1,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 virtualenv at ~/Desktop/Xray" project-jdk-type="Python SDK" />
4
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/SAStools.iml" filepath="$PROJECT_DIR$/.idea/SAStools.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,52 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ChangeListManager">
4
+ <list default="true" id="09f946be-75db-402c-b25b-84222a289980" name="Changes" comment="" />
5
+ <option name="SHOW_DIALOG" value="false" />
6
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
7
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
8
+ <option name="LAST_RESOLUTION" value="IGNORE" />
9
+ </component>
10
+ <component name="Git.Settings">
11
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
12
+ </component>
13
+ <component name="ProjectColorInfo"><![CDATA[{
14
+ "associatedIndex": 5
15
+ }]]></component>
16
+ <component name="ProjectId" id="3HAdiFu7fWFBVf6cvVccj9EsM0S" />
17
+ <component name="ProjectViewState">
18
+ <option name="hideEmptyMiddlePackages" value="true" />
19
+ <option name="showLibraryContents" value="true" />
20
+ </component>
21
+ <component name="PropertiesComponent"><![CDATA[{
22
+ "keyToString": {
23
+ "ModuleVcsDetector.initialDetectionPerformed": "true",
24
+ "RunOnceActivity.ShowReadmeOnStart": "true",
25
+ "com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
26
+ "git-widget-placeholder": "master",
27
+ "junie.onboarding.icon.badge.shown": "true",
28
+ "nodejs_package_manager_path": "npm",
29
+ "to.speed.mode.migration.done": "true",
30
+ "vue.rearranger.settings.migration": "true"
31
+ }
32
+ }]]></component>
33
+ <component name="SharedIndexes">
34
+ <attachedChunks>
35
+ <set>
36
+ <option value="bundled-js-predefined-d6986cc7102b-a71380e98a7c-JavaScript-PY-252.28238.29" />
37
+ <option value="bundled-python-sdk-a101402ee41c-968fe969f28a-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-252.28238.29" />
38
+ </set>
39
+ </attachedChunks>
40
+ </component>
41
+ <component name="TaskManager">
42
+ <task active="true" id="Default" summary="Default task">
43
+ <changelist id="09f946be-75db-402c-b25b-84222a289980" name="Changes" comment="" />
44
+ <created>1785314933654</created>
45
+ <option name="number" value="Default" />
46
+ <option name="presentableId" value="Default" />
47
+ <updated>1785314933654</updated>
48
+ <workItem from="1785314934765" duration="1000" />
49
+ </task>
50
+ <servers />
51
+ </component>
52
+ </project>
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: ScatTools
3
+ Version: 0.0.1
4
+ Summary: Tools for X-ray and neutron scattering analysis
5
+ Project-URL: Homepage, https://github.com/chelberserker/ScatTools/
6
+ Author: Egor A. Bersenev
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.8
11
+ Requires-Dist: h5py
12
+ Requires-Dist: matplotlib
13
+ Requires-Dist: numpy
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Scatter Analysis
17
+
18
+ A Python package providing tools for the analysis of X-ray and neutron scattering data (SAXS, SANS, and GID).
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install ScatTools
24
+ ```
25
+
26
+ ## Features
27
+
28
+ - **GID**: Analysis of Grazing Incidence Diffraction data. Calculates crystallographic parameters based on scattering vectors.
29
+ - **SAS**: Analysis of Small Angle Scattering data, including Small Angle X-ray Scattering (SAXS) and Small Angle Neutron Scattering (SANS) with support for plotting and data loading.
30
+
31
+ ## Documentation
32
+
33
+ Documentation will be made available shortly.
34
+
35
+ ## Usage Example
36
+
37
+ ```python
38
+ from gid import calculate_cell_parameters
39
+
40
+ # Calculate parameters based on scattering vectors
41
+ params = calculate_cell_parameters(qxy1=1.0, qxy2=1.0, qxy3=1.0, qz1=0.1, qz2=0.1, qz3=0.1)
42
+ print(params)
43
+ ```
@@ -0,0 +1,28 @@
1
+ # Scatter Analysis
2
+
3
+ A Python package providing tools for the analysis of X-ray and neutron scattering data (SAXS, SANS, and GID).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install ScatTools
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **GID**: Analysis of Grazing Incidence Diffraction data. Calculates crystallographic parameters based on scattering vectors.
14
+ - **SAS**: Analysis of Small Angle Scattering data, including Small Angle X-ray Scattering (SAXS) and Small Angle Neutron Scattering (SANS) with support for plotting and data loading.
15
+
16
+ ## Documentation
17
+
18
+ Documentation will be made available shortly.
19
+
20
+ ## Usage Example
21
+
22
+ ```python
23
+ from gid import calculate_cell_parameters
24
+
25
+ # Calculate parameters based on scattering vectors
26
+ params = calculate_cell_parameters(qxy1=1.0, qxy2=1.0, qxy3=1.0, qz1=0.1, qz2=0.1, qz3=0.1)
27
+ print(params)
28
+ ```
@@ -0,0 +1,20 @@
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line, and also
5
+ # from the environment for the first two.
6
+ SPHINXOPTS ?=
7
+ SPHINXBUILD ?= sphinx-build
8
+ SOURCEDIR = .
9
+ BUILDDIR = _build
10
+
11
+ # Put it first so that "make" without argument is like "make help".
12
+ help:
13
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14
+
15
+ .PHONY: help Makefile
16
+
17
+ # Catch-all target: route all unknown targets to Sphinx using the new
18
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19
+ %: Makefile
20
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@@ -0,0 +1,43 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # For the full list of built-in configuration values, see the documentation:
4
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
+
6
+ import os
7
+ import sys
8
+ sys.path.insert(0, os.path.abspath('../src'))
9
+
10
+ # -- Project information -----------------------------------------------------
11
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
12
+
13
+ project = 'ScatTools'
14
+ copyright = '2025, Egor A. Bersenev'
15
+ author = 'Egor A. Bersenev'
16
+
17
+ # -- General configuration ---------------------------------------------------
18
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
19
+
20
+ extensions = [
21
+ 'sphinx.ext.autodoc',
22
+ 'sphinx.ext.viewcode',
23
+ 'sphinx.ext.napoleon',
24
+ 'sphinx_rtd_theme',
25
+ 'nbsphinx',
26
+ ]
27
+
28
+ autodoc_member_order = 'groupwise'
29
+
30
+ autodoc_default_options = {
31
+ 'members': True, # Document members (methods/attributes)
32
+ 'member-order': 'groupwise', # Enforce grouping by type
33
+ 'undoc-members': True, # Include members without docstrings
34
+ 'show-inheritance': True, # Show parent classes
35
+ }
36
+
37
+ autodoc_typehints = "description" # Moves type hints into the description instead of signature
38
+
39
+ templates_path = ['_templates']
40
+ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
41
+
42
+ html_theme = 'classic'
43
+ html_static_path = ['_static']
@@ -0,0 +1,7 @@
1
+ GID Module
2
+ ==========
3
+
4
+ .. automodule:: gid.gid
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,17 @@
1
+ .. scatter-analysis documentation master file
2
+
3
+ Welcome to scatter-analysis's documentation!
4
+ ============================================
5
+
6
+ .. toctree::
7
+ :maxdepth: 2
8
+ :caption: Contents:
9
+
10
+ modules
11
+
12
+ Indices and tables
13
+ ==================
14
+
15
+ * :ref:`genindex`
16
+ * :ref:`modindex`
17
+ * :ref:`search`
@@ -0,0 +1,8 @@
1
+ Modules
2
+ =======
3
+
4
+ .. toctree::
5
+ :maxdepth: 4
6
+
7
+ gid
8
+ sas
@@ -0,0 +1,7 @@
1
+ SAS Module
2
+ ==========
3
+
4
+ .. automodule:: sas.sas
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ScatTools"
7
+ version = "0.0.1"
8
+ description = "Tools for X-ray and neutron scattering analysis"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ authors = [
12
+ { name = "Egor A. Bersenev" },
13
+ ]
14
+ dependencies = [
15
+ "numpy",
16
+ "matplotlib",
17
+ "h5py",
18
+ ]
19
+ classifiers = [
20
+ "Programming Language :: Python :: 3",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/chelberserker/ScatTools/"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["src/gid", "src/sas"]
@@ -0,0 +1,6 @@
1
+ """
2
+ Package for the analysis of X-ray/neutron scattering data:
3
+ SAXS, SANS, GID
4
+ """
5
+
6
+ __version__ = '0.0.1'
@@ -0,0 +1,2 @@
1
+ from .gid import calculate_cell_parameters as calculate_cell_parameters
2
+ from .gid import calculate_q_values as calculate_q_values
@@ -0,0 +1,154 @@
1
+ import logging
2
+ import math
3
+
4
+ import numpy as np
5
+
6
+ logging.basicConfig(level=logging.INFO, format='%(message)s')
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ def calculate_cell_parameters(qxy1, qxy2, qxy3, qz1, qz2, qz3):
11
+ """
12
+ Calculates crystallographic parameters based on scattering vectors.
13
+ Args:
14
+ qxy1 (float): q_{xy} position of the first peak
15
+ qxy2 (float): q_{xy} position of the second peak
16
+ qxy3 (float): q_{xy} position of the third peak
17
+ qz1 (float): q_{z} position of the first peak
18
+ qz2 (float): q_{z} position of the second peak
19
+ qz3 (float): q_{z} position of the third peak
20
+ Returns:
21
+
22
+ """
23
+
24
+ vectors = sorted([
25
+ (qxy1, qz1),
26
+ (qxy2, qz2),
27
+ (qxy3, qz3)
28
+ ], key=lambda v: v[0])
29
+
30
+ qx10, qz10 = vectors[0]
31
+ qx01, qz01 = vectors[1]
32
+ qx11, qz11 = vectors[2]
33
+
34
+ cos_g = (qx10 ** 2 + qx01 ** 2 - qx11 ** 2) / (2 * qx10 * qx01)
35
+ if abs(cos_g) > 1.0:
36
+ logger.warning('Error: Check input values (cos G > 1).')
37
+ return None
38
+
39
+ gam_rad = np.acos(cos_g) # Angle between A and B in real space
40
+
41
+ a = 2 * np.pi / (qx10 * np.sin(gam_rad))
42
+ b = 2 * np.pi / (qx01 * np.sin(gam_rad))
43
+
44
+
45
+ if abs(qz10 + qz01 - qz11) > 0.03:
46
+ qz10 = -qz10
47
+
48
+ if abs(qz10 + qz01 - qz11) > 0.03:
49
+ qz11 = -qz11
50
+
51
+ # Normal components
52
+ nz = qx10 * qx01 * np.sin(gam_rad)
53
+ nx = -qz10 * qx01 * np.sin(gam_rad)
54
+ ny = -(qx10 * qz01 + qz10 * qx01 * np.cos(gam_rad))
55
+ nmod = np.sqrt(nx ** 2 + ny ** 2 + nz ** 2)
56
+
57
+ if nmod == 0 or abs(nz / nmod) > 1.0:
58
+ logger.warning('Error: Check input values (Nz/Nmod > 1).')
59
+ return None
60
+
61
+ t3_rad = math.acos(nz / nmod)
62
+
63
+ # Azimuth: Angle between projection of N on XOY where OX==a* and OY==b*
64
+ if t3_rad == 0.0:
65
+ azimuth3_rad = 0.0
66
+ else:
67
+ if nx == 0.0:
68
+ azimuth3_rad = 0.0
69
+ else:
70
+ azimuth3_rad = np.atan(ny / nx)
71
+
72
+ area = a * b * np.sin(gam_rad)
73
+
74
+ # Convert angles to degrees
75
+ gam_deg = np.rad2deg(gam_rad)
76
+ if gam_deg > 180.0:
77
+ gam_deg = 360.0 - gam_deg
78
+
79
+ t3_deg = np.rad2deg(t3_rad)
80
+
81
+ # Azimuth = counter-clockwise rotation from real space A-vector
82
+ if azimuth3_rad != 0.0:
83
+ azimuth3_deg = np.rad2deg(azimuth3_rad) + (gam_deg - 90.0)
84
+ else:
85
+ azimuth3_deg = 0.0
86
+
87
+ return {
88
+ "a": np.round(a, 5),
89
+ "b": np.round(b, 5),
90
+ "gamma": np.round(gam_deg,2),
91
+ "tilt": np.round(t3_deg,2),
92
+ "azimuth": np.round(azimuth3_deg,2),
93
+ "area": np.round(area, 3)
94
+ }
95
+
96
+ def calculate_q_values(a, b, gamma, tilt, azimuth):
97
+ """
98
+ Calculates the scattering vectors (qxy, qz) based on 2D crystallographic parameters.
99
+ Args:
100
+ a (float): Unit cell parameter a
101
+ b (float): Unit cell parameter b
102
+ gamma (float): Angle between a and b in real space (degrees)
103
+ tilt (float): Tilt angle of the lattice (degrees)
104
+ azimuth (float): Azimuthal angle of the tilt (degrees)
105
+ Returns:
106
+ dict: The qxy and qz scattering vectors for the first three peaks
107
+ """
108
+ gam_rad = np.deg2rad(gamma)
109
+ t3_rad = np.deg2rad(tilt)
110
+
111
+ # 1. Reverse A and B reciprocal relationships to get qxy1 (qx10) and qxy2 (qx01)
112
+ qx10 = 2 * np.pi / (a * np.sin(gam_rad))
113
+ qx01 = 2 * np.pi / (b * np.sin(gam_rad))
114
+
115
+ # 2. Calculate qxy3 (qx11) using the reciprocal space law of cosines
116
+ qx11 = np.sqrt(qx10**2 + qx01**2 - 2 * qx10 * qx01 * np.cos(gam_rad))
117
+
118
+ # 3. Reverse the azimuth logic
119
+ # azimuth3_deg = azimuth_internal_deg + (gam_deg - 90.0)
120
+ azimuth_internal_deg = azimuth - (gamma - 90.0)
121
+ azimuth_internal_rad = np.deg2rad(azimuth_internal_deg)
122
+
123
+ # 4. Reconstruct the normal vector components
124
+ nz = qx10 * qx01 * np.sin(gam_rad)
125
+
126
+ # Guard against perfectly vertical tilt dividing by zero
127
+ if np.cos(t3_rad) == 0.0:
128
+ return None
129
+
130
+ nmod = nz / np.cos(t3_rad)
131
+
132
+ # Extract nx and ny using the inverted azimuthal angles
133
+ nxy = np.sqrt(max(0, nmod**2 - nz**2))
134
+ nx = nxy * np.cos(azimuth_internal_rad)
135
+ ny = nxy * np.sin(azimuth_internal_rad)
136
+
137
+ # 5. Reverse the cross product equations to solve for qz10 and qz01
138
+ # nx = -qz10 * qx01 * sin(gamma)
139
+ qz10 = nx / (qx01 * np.sin(gam_rad))
140
+
141
+ # ny = -(qx10 * qz01 + qz10 * qx01 * cos(gamma))
142
+ qz01 = (-ny - qz10 * qx01 * np.cos(gam_rad)) / qx10
143
+
144
+ # 6. Reconstruct qz11 (assuming ideal constructive addition for the 1,1 peak)
145
+ qz11 = qz10 + qz01
146
+
147
+ return {
148
+ "qxy1": np.round(qx10, 5),
149
+ "qz1": np.round(qz10, 5),
150
+ "qxy2": np.round(qx01, 5),
151
+ "qz2": np.round(qz01, 5),
152
+ "qxy3": np.round(qx11, 5),
153
+ "qz3": np.round(qz11, 5)
154
+ }
@@ -0,0 +1,2 @@
1
+ from .sas import D11_SANS as D11_SANS
2
+ from .sas import ID02_SAXS as ID02_SAXS
@@ -0,0 +1,96 @@
1
+ import h5py
2
+ import matplotlib.pyplot as plt
3
+ import numpy as np
4
+
5
+
6
+ class D11_SANS:
7
+
8
+ def __init__(self, filename, data=True):
9
+ self.q = np.array([])
10
+ self.I = np.array([])
11
+ self.I_err = np.array([])
12
+ self.q_err = np.array([])
13
+ self.q_fit = np.array([])
14
+ self.I_fit = np.array([])
15
+ self.sample_name = ''
16
+ if data:
17
+ self.load_data(filename)
18
+ else:
19
+ self.load_fit(filename)
20
+
21
+ def __repr__(self):
22
+ return self.sample_name
23
+
24
+ def get_sample_name(self):
25
+ return self.sample_name
26
+
27
+ def load_data(self, filename):
28
+ with open(filename, 'r') as f:
29
+ a = f.read()
30
+ self.sample_name = a.split('Subtitle:')[1].split('\n')[0].replace(' ', '')
31
+ data = np.loadtxt(filename, skiprows=53).T
32
+ self.q = data[0] * 10
33
+ self.I = data[1]
34
+ self.I_err = data[2]
35
+ self.q_err = data[3] * 10
36
+
37
+ def plot(self, ax=None, bckg=0.0, label=None):
38
+ if not ax:
39
+ _fig, ax = plt.subplots(1, 1)
40
+
41
+ if not label:
42
+ label = self.sample_name
43
+
44
+ if isinstance(bckg, float):
45
+ ax.errorbar(self.q, self.I - bckg, yerr=self.I_err, label=label, fmt='.', capsize=3, alpha=0.25)
46
+ else:
47
+ ax.errorbar(self.q, self.I - bckg.I, yerr=self.I_err, label=label, fmt='.', capsize=3, alpha=0.25)
48
+ ax.set_xlabel('$q, \\mathrm{nm}^{-1}$')
49
+ ax.set_ylabel('$\\mathrm{\\Delta}\\Sigma / \\mathrm{\\Delta}\\Omega, \\mathrm{cm}^{-1}$')
50
+ ax.loglog()
51
+ ax.legend()
52
+
53
+
54
+ class ID02_SAXS:
55
+ def __init__(self, filename, data=True, sample_thickness=0.2):
56
+ self.q = np.array([])
57
+ self.I = np.array([])
58
+ self.I_err = np.array([])
59
+ self.q_fit = np.array([])
60
+ self.I_fit = np.array([])
61
+ self.sample_name = ''
62
+ self.sample_thickness = sample_thickness # for 2 mm capillary to convert into 1/cm
63
+ if data:
64
+ self.load_data(filename)
65
+ else:
66
+ self.load_fit(filename)
67
+
68
+ def __repr__(self):
69
+ return self.sample_name
70
+
71
+ def load_fit(self, filename):
72
+ fit = np.loadtxt(filename).T
73
+ # print(fit)
74
+ self.q_fit = fit[0]
75
+ self.I_fit = fit[1]
76
+
77
+ def load_data(self, filename):
78
+ with h5py.File(filename, 'r') as file:
79
+ self.I = np.array(file['entry_0000']['saxsutilities']['data']['I'])[0] / self.sample_thickness
80
+ self.I_err = np.array(file['entry_0000']['saxsutilities']['data']['Idev'])[0] / self.sample_thickness
81
+ self.q = np.array(file['entry_0000']['saxsutilities']['data']['q'])
82
+ self.sample_name = str(file['entry_0000']['saxsutilities']['data']['header_array']['title'][()]).split("\'")[1]
83
+
84
+ def plot(self, ax=None, norm_factor=1, label=None):
85
+ if not ax:
86
+ _fig, ax = plt.subplots(1, 1)
87
+
88
+ if not label:
89
+ label = self.sample_name
90
+
91
+ ax.errorbar(self.q, self.I / norm_factor, self.I_err / norm_factor, fmt='o', capsize=2, linewidth=1,
92
+ markersize=1, label=label)
93
+ ax.set_xlabel('$q, \\mathrm{nm}^{-1}$')
94
+ ax.set_ylabel('$\\mathrm{Intensity, cm}^{-1}$')
95
+ ax.legend()
96
+ ax.loglog()
@@ -0,0 +1,139 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "id": "initial_id",
6
+ "metadata": {
7
+ "collapsed": true,
8
+ "ExecuteTime": {
9
+ "end_time": "2026-07-29T14:28:04.733134Z",
10
+ "start_time": "2026-07-29T14:28:04.729842Z"
11
+ }
12
+ },
13
+ "source": "from src.gid import calculate_cell_parameters, calculate_q_values",
14
+ "outputs": [],
15
+ "execution_count": 6
16
+ },
17
+ {
18
+ "metadata": {
19
+ "ExecuteTime": {
20
+ "end_time": "2026-07-29T14:28:06.207859Z",
21
+ "start_time": "2026-07-29T14:28:06.205370Z"
22
+ }
23
+ },
24
+ "cell_type": "code",
25
+ "source": [
26
+ "example_qxy1 = 0.934998\n",
27
+ "example_qxy2 = 1.308997\n",
28
+ "example_qxy3 = 1.379241\n",
29
+ "example_qz1 = 0.431857\n",
30
+ "example_qz2 = 0.604600\n",
31
+ "example_qz3 = 0.172743\n",
32
+ "cell_parameters = calculate_cell_parameters(example_qxy1, example_qxy2, example_qxy3, example_qz1, example_qz2, example_qz3)"
33
+ ],
34
+ "id": "8995fbab8e9a5a1c",
35
+ "outputs": [],
36
+ "execution_count": 7
37
+ },
38
+ {
39
+ "metadata": {
40
+ "ExecuteTime": {
41
+ "end_time": "2026-07-29T14:28:06.771160Z",
42
+ "start_time": "2026-07-29T14:28:06.769062Z"
43
+ }
44
+ },
45
+ "cell_type": "code",
46
+ "source": [
47
+ "for param in cell_parameters:\n",
48
+ " print(f\"{param} = {cell_parameters[param]}\")"
49
+ ],
50
+ "id": "6e7c5042d408d770",
51
+ "outputs": [
52
+ {
53
+ "name": "stdout",
54
+ "output_type": "stream",
55
+ "text": [
56
+ "a = 7.0\n",
57
+ "b = 5.0\n",
58
+ "gamma = 73.74\n",
59
+ "tilt = 30.0\n",
60
+ "azimuth = -53.13\n",
61
+ "area = 33.6\n"
62
+ ]
63
+ }
64
+ ],
65
+ "execution_count": 8
66
+ },
67
+ {
68
+ "metadata": {
69
+ "ExecuteTime": {
70
+ "end_time": "2026-07-29T14:28:07.270147Z",
71
+ "start_time": "2026-07-29T14:28:07.267474Z"
72
+ }
73
+ },
74
+ "cell_type": "code",
75
+ "source": "q_vectors = calculate_q_values(7, 5, 73.74, 30, -53.13)",
76
+ "id": "7d152be4ad9aab7b",
77
+ "outputs": [],
78
+ "execution_count": 9
79
+ },
80
+ {
81
+ "metadata": {
82
+ "ExecuteTime": {
83
+ "end_time": "2026-07-29T14:28:07.782791Z",
84
+ "start_time": "2026-07-29T14:28:07.780466Z"
85
+ }
86
+ },
87
+ "cell_type": "code",
88
+ "source": [
89
+ "for param in q_vectors:\n",
90
+ " print(f\"{param} = {q_vectors[param]}\")"
91
+ ],
92
+ "id": "b7bc54cc671b0c4b",
93
+ "outputs": [
94
+ {
95
+ "name": "stdout",
96
+ "output_type": "stream",
97
+ "text": [
98
+ "qxy1 = 0.935\n",
99
+ "qz1 = 0.43186\n",
100
+ "qxy2 = 1.309\n",
101
+ "qz2 = 0.26603\n",
102
+ "qxy3 = 1.37924\n",
103
+ "qz3 = 0.69788\n"
104
+ ]
105
+ }
106
+ ],
107
+ "execution_count": 10
108
+ },
109
+ {
110
+ "metadata": {},
111
+ "cell_type": "code",
112
+ "outputs": [],
113
+ "execution_count": null,
114
+ "source": "",
115
+ "id": "7aa839e13949494b"
116
+ }
117
+ ],
118
+ "metadata": {
119
+ "kernelspec": {
120
+ "display_name": "Python 3",
121
+ "language": "python",
122
+ "name": "python3"
123
+ },
124
+ "language_info": {
125
+ "codemirror_mode": {
126
+ "name": "ipython",
127
+ "version": 2
128
+ },
129
+ "file_extension": ".py",
130
+ "mimetype": "text/x-python",
131
+ "name": "python",
132
+ "nbconvert_exporter": "python",
133
+ "pygments_lexer": "ipython2",
134
+ "version": "2.7.6"
135
+ }
136
+ },
137
+ "nbformat": 4,
138
+ "nbformat_minor": 5
139
+ }