Skip to content

Commit 644bec5

Browse files
Merge pull request #148 from EasyScience/develop
Release 0.1.5
2 parents 68b4ead + 1a414c1 commit 644bec5

21 files changed

+7718
-805
lines changed

.github/workflows/release-drafter.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,21 @@ jobs:
1616
- uses: release-drafter/release-drafter@v6
1717
env:
1818
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19+
20+
- name: Check-out repository
21+
uses: actions/checkout@v4
22+
23+
# Zips the examples directory
24+
- name: Zip examples directory
25+
run: zip -r examples.zip examples/
26+
27+
# Uploads the zipped examples directory to the release draft
28+
- name: Upload zipped examples directory
29+
uses: actions/upload-release-asset@v1
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32+
with:
33+
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the create_release step above
34+
asset_path: ./examples.zip
35+
asset_name: examples.zip
36+
asset_content_type: application/zip

.github/workflows/test-ipynb.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ jobs:
8686
shell: bash
8787
run: >
8888
pytest
89-
--nbmake examples/*ipynb
89+
--nbmake examples
90+
--ignore-glob='examples/*emcee*'
9091
--nbmake-timeout=300
9192
--color=yes
9293
-n=auto

.github/workflows/test-package.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ jobs:
117117
shell: bash
118118
run: >
119119
pytest
120-
--nbmake examples/*ipynb
120+
--nbmake examples
121+
--ignore-glob='examples/*emcee*'
121122
--nbmake-timeout=300
122123
--color=yes
123124
-n=auto

easydiffraction/Job.py

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ def __init__(
140140
self.sample = sample # container for phases
141141
self.interface = self.sample._interface
142142
self.analysis = analysis
143+
self.update_job_type()
143144
# necessary for the fitter
144145
# TODO: remove the dependency on kwargs
145146
self._kwargs = {}
@@ -329,7 +330,14 @@ def update_job_type(self) -> None:
329330
self.type.is_tof = self.experiment.is_tof
330331
self.type.is_sc = self.experiment.is_single_crystal
331332
self.type.is_2d = self.experiment.is_2d
332-
333+
# radiation
334+
if hasattr(self.sample, 'pattern') and self.sample.pattern is not None:
335+
if self.type.is_xray:
336+
self.sample.pattern.radiation = "x-ray"
337+
elif self.type.is_neut:
338+
self.sample.pattern.radiation = "neutron"
339+
340+
# axis
333341
if self.type.is_tof:
334342
self._x_axis_name = "time"
335343
if self.pattern is not None:
@@ -587,16 +595,27 @@ def fit(self, **kwargs):
587595
if result is None:
588596
raise ValueError("Fitting failed")
589597

598+
# Print fitting result. If in a notebook, use emojis.
599+
success_msg = "Success"
600+
failure_msg = "Failure"
601+
duration_msg = f"{end - start:.2f} s"
602+
if self.is_notebook():
603+
success_msg = f'🥳 {success_msg}'
604+
failure_msg = f'😩 {failure_msg}'
605+
duration_msg = f'⌛ {duration_msg}'
606+
print("Fitting result")
590607
if result.success:
591-
print("Fitting successful")
592-
print(f"Duration: {end - start:.2f} s")
593-
print(f"Reduced chi: {result.reduced_chi:.2f}")
608+
reduced_chi_msg = f"{result.reduced_chi:.2f}"
609+
if self.is_notebook():
610+
reduced_chi_msg = f'👍 {reduced_chi_msg}'
611+
print(f'Status: {success_msg}')
612+
print(f'Duration: {duration_msg}')
613+
print(f'Reduced χ²: {reduced_chi_msg}')
594614
else:
595-
print("Fitting failed.")
615+
print(f'Status: {failure_msg}')
596616

597617
self.fitting_results = result
598618

599-
600619
###### UTILITY METHODS ######
601620
def add_datastore(self, datastore: xr.Dataset):
602621
'''
@@ -632,16 +651,16 @@ def show_crystal_structure(self, id=None):
632651
phase = self.phases[id]
633652
cif = phase.cif
634653

635-
structure_view = py3Dmol.view(linked=False)
654+
structure_view = py3Dmol.view(width=540, height=480, linked=False)
636655
structure_view.addModel(cif, 'cif')
637656
structure_view.setStyle({'sphere': {'colorscheme': 'Jmol', 'scale': .2},
638657
'stick': {'colorscheme': 'Jmol', 'radius': 0.1}})
639658
if importlib.util.find_spec("darkdetect") is not None and darkdetect.isDark():
640659
structure_view.setBackgroundColor('#111')
641660
structure_view.addUnitCell()
642661
structure_view.replicateUnitCell(2, 2, 2)
643-
structure_view.zoomTo()
644-
structure_view.show()
662+
structure_view.zoomTo() # To zoom in to the center of the structure
663+
structure_view.show() # To display the contents of the view object on Jupyter notebook.
645664

646665
def print_data(self):
647666
'''
@@ -728,6 +747,62 @@ def show_experiment_chart(self, show_legend=True):
728747

729748
fig.show()
730749

750+
def show_simulation_chart(self, show_legend=True):
751+
'''
752+
Show the simulation chart.
753+
'''
754+
if importlib.util.find_spec("plotly") is None:
755+
print("Warning: Plotly not installed. Try `pip install plotly`.")
756+
return
757+
758+
if self.type.is_pd and self.type.is_cwl:
759+
x_axis_title = '2θ (degree)'
760+
x = np.arange(self.instrument.twotheta_range_min.raw_value,
761+
self.instrument.twotheta_range_max.raw_value + self.instrument.twotheta_range_inc.raw_value,
762+
self.instrument.twotheta_range_inc.raw_value)
763+
elif self.type.is_pd and self.type.is_tof:
764+
x_axis_title = 'TOF (µs)'
765+
x = np.arange(self.instrument.tof_range_min.raw_value,
766+
self.instrument.tof_range_max.raw_value + self.instrument.tof_range_inc.raw_value,
767+
self.instrument.tof_range_inc.raw_value)
768+
else:
769+
print(f"Warning: Simulation chart not available for this type of job '{self.type}'")
770+
print("Supported types: 'pd-cwl' and 'pd-tof'")
771+
772+
y_calc = self.calculate_profile(x)
773+
774+
main_y_range = y_calc.max() - y_calc.min()
775+
main_y_min = y_calc.min() - main_y_range / 10
776+
main_y_max = y_calc.max() + main_y_range / 10
777+
778+
trace_calc = go.Scatter(
779+
x=x,
780+
y=y_calc,
781+
line=dict(color='rgb(214, 39, 40)'),
782+
mode='lines',
783+
name='Total calculated (Icalc)'
784+
)
785+
786+
data = [trace_calc]
787+
788+
layout = go.Layout(
789+
autosize=True,
790+
margin=dict(autoexpand=True,
791+
r=30, t=30, b=45),
792+
legend=dict(yanchor="top", y=1.0,
793+
xanchor="right", x=1.0),
794+
xaxis=dict(title_text=x_axis_title),
795+
yaxis=dict(title_text='Icalc', range=[main_y_min, main_y_max]),
796+
)
797+
798+
fig = go.Figure(data=data, layout=layout)
799+
800+
fig.update_xaxes(showline=True, mirror=True, zeroline=False)
801+
fig.update_yaxes(showline=True, mirror=True, zeroline=False)
802+
fig.update_layout(showlegend=show_legend)
803+
804+
fig.show()
805+
731806
def show_analysis_chart(self, show_legend=True):
732807
'''
733808
Show the analysis chart.

easydiffraction/Profiles/P1D.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from easyscience.Datasets.xarray import xr
1616
from easyscience.Objects.ObjectClasses import BaseObj
17+
from easyscience.Objects.ObjectClasses import Descriptor
1718
from easyscience.Objects.ObjectClasses import Parameter
1819

1920
from easydiffraction.components.polarization import PolarizedBeam
@@ -244,6 +245,48 @@ class Instrument1DCWParameters(BaseObj):
244245
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_instr/",
245246
"value": 0.0,
246247
"fixed": True,
248+
},
249+
"twotheta_range_min": {
250+
"name": "twotheta_range_min",
251+
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_meas/",
252+
"value": 10.0,
253+
"fixed": True,
254+
"enabled": False,
255+
},
256+
"twotheta_range_max": {
257+
"name": "twotheta_range_max",
258+
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_meas/",
259+
"value": 170.0,
260+
"fixed": True,
261+
"enabled": False,
262+
},
263+
"twotheta_range_inc": {
264+
"name": "twotheta_range_inc",
265+
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_meas/",
266+
"value": 0.1,
267+
"fixed": True,
268+
"enabled": False,
269+
},
270+
"tof_range_min": {
271+
"name": "tof_range_min",
272+
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_meas/",
273+
"value": 10000.0,
274+
"fixed": True,
275+
"enabled": False,
276+
},
277+
"tof_range_max": {
278+
"name": "tof_range_max",
279+
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_meas/",
280+
"value": 100000.0,
281+
"fixed": True,
282+
"enabled": False,
283+
},
284+
"tof_range_inc": {
285+
"name": "tof_range_inc",
286+
"url": "https://docs.easydiffraction.org/lib/project/dictionaries/_pd_meas/",
287+
"value": 5.0,
288+
"fixed": True,
289+
"enabled": False,
247290
}
248291
}
249292

@@ -257,6 +300,12 @@ class Instrument1DCWParameters(BaseObj):
257300
reflex_asymmetry_p2: ClassVar[Parameter]
258301
reflex_asymmetry_p3: ClassVar[Parameter]
259302
reflex_asymmetry_p4: ClassVar[Parameter]
303+
twotheta_range_min: ClassVar[Descriptor]
304+
twotheta_range_max: ClassVar[Descriptor]
305+
twotheta_range_inc: ClassVar[Descriptor]
306+
tof_range_min: ClassVar[Descriptor]
307+
tof_range_max: ClassVar[Descriptor]
308+
tof_range_inc: ClassVar[Descriptor]
260309

261310
def __init__(
262311
self,
@@ -270,6 +319,12 @@ def __init__(
270319
reflex_asymmetry_p2: Optional[Union[Parameter, float]] = None,
271320
reflex_asymmetry_p3: Optional[Union[Parameter, float]] = None,
272321
reflex_asymmetry_p4: Optional[Union[Parameter, float]] = None,
322+
twotheta_range_min: Optional[Union[Descriptor, float]] = None,
323+
twotheta_range_max: Optional[Union[Descriptor, float]] = None,
324+
twotheta_range_inc: Optional[Union[Descriptor, float]] = None,
325+
tof_range_min: Optional[Union[Descriptor, float]] = None,
326+
tof_range_max: Optional[Union[Descriptor, float]] = None,
327+
tof_range_inc: Optional[Union[Descriptor, float]] = None,
273328
interface: Optional[iF] = None,
274329
):
275330
super(Instrument1DCWParameters, self).__init__(
@@ -299,6 +354,18 @@ def __init__(
299354
self.reflex_asymmetry_p3 = reflex_asymmetry_p3
300355
if reflex_asymmetry_p4 is not None:
301356
self.reflex_asymmetry_p4 = reflex_asymmetry_p4
357+
if twotheta_range_min is not None:
358+
self.twotheta_range_min = twotheta_range_min
359+
if twotheta_range_max is not None:
360+
self.twotheta_range_max = twotheta_range_max
361+
if twotheta_range_inc is not None:
362+
self.twotheta_range_inc = twotheta_range_inc
363+
if tof_range_min is not None:
364+
self.tof_range_min = tof_range_min
365+
if tof_range_max is not None:
366+
self.tof_range_max = tof_range_max
367+
if tof_range_inc is not None:
368+
self.tof_range_inc = tof_range_inc
302369
self.name = self._name
303370
self.interface = interface
304371

easydiffraction/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .components.phase import Phases as Phases
1010
from .components.site import Atoms as Atoms
1111
from .components.site import Site as Site
12+
from .io.download import download_from_repository
1213
from .Job import DiffractionJob as Job
1314

14-
__all__ = ['Job']
15+
__all__ = ['Job', 'download_from_repository']

easydiffraction/io/download.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-FileCopyrightText: 2024 EasyDiffraction contributors
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
# © 2021-2024 Contributors to the EasyDiffraction project <https://github.com/easyscience/EasyDiffraction
4+
5+
import pooch
6+
7+
8+
def download_from_repository(fname : str, branch : str = 'master', destination : str = 'data'):
9+
'''
10+
This function downloads a file from the EasyDiffraction repository on GitHub.
11+
:param fname: The name of the file to download
12+
:param destination: The destination folder to save the file
13+
:return: None
14+
'''
15+
organisation = 'EasyScience'
16+
repository = 'EasyDiffractionLib'
17+
source = 'examples/data'
18+
url = f'https://raw.githubusercontent.com/{organisation}/{repository}/refs/heads/{branch}/{source}/{fname}'
19+
pooch.retrieve(
20+
url=url,
21+
known_hash=None,
22+
fname=fname,
23+
path=destination,
24+
)

0 commit comments

Comments
 (0)