Skip to content

Commit

Permalink
Working prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
lucas-wilkins committed Sep 4, 2023
1 parent 72afb91 commit bf5f089
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 26 deletions.
21 changes: 15 additions & 6 deletions src/sas/qtgui/Perspectives/ParticleEditor/DesignWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ def onRadiusChanged(self):
def onTimeEstimateParametersChanged(self):
""" Called when the number of samples changes """

# TODO: This needs to be updated based on the number of angular samples now
# Should have a n_points term
# Should have a n_points*n_angles

# Update the estimate of time
# Assume the amount of time is just determined by the number of
Expand Down Expand Up @@ -250,6 +253,13 @@ def angularDistribution(self) -> AngularDistribution:
""" Get the AngularDistribution object that represents the GUI selected orientational distribution"""
return self.angularSamplingMethodSelector.generate_sampler()

def qSampling(self) -> QSample:
q_min = float(self.qMinBox.text()) # TODO: Use better box
q_max = float(self.qMaxBox.text())
n_q = int(self.qSamplesBox.value())
is_log = bool(self.useLogQ.isChecked())

return QSample(q_min, q_max, n_q, is_log)

def spatialSampling(self) -> SpatialDistribution:
""" Calculate the spatial sampling object based on current gui settings"""
Expand All @@ -261,11 +271,11 @@ def spatialSampling(self) -> SpatialDistribution:
seed = int(self.randomSeed.text()) if self.fixRandomSeed.isChecked() else None

if sample_type == 0:
return GridSampling(radius=radius, n_points=n_points, seed=seed)
return GridSampling(radius=radius, desired_points=n_points)
# return MixedSphereSample(radius=radius, n_points=n_points, seed=seed)

elif sample_type == 1:
return UniformCubeSampling(radius=radius, n_points=n_points, seed=seed)
return UniformCubeSampling(radius=radius, desired_points=n_points, seed=seed)
# return MixedCubeSample(radius=radius, n_points=n_points, seed=seed)

else:
Expand Down Expand Up @@ -307,13 +317,15 @@ def scatteringCalculation(self) -> ScatteringCalculation:
is to be passed to the solver"""
angular_distribution = self.angularDistribution()
spatial_sampling = self.spatialSampling()
q_sampling = self.qSampling()
particle_definition = self.particleDefinition()
parameter_definition = self.parametersForCalculation()
polarisation_vector = self.polarisationVector()
seed = self.currentSeed()
bounding_surface_check = self.continuityCheck.isChecked()

return ScatteringCalculation(
q_sampling=q_sampling,
angular_sampling=angular_distribution,
spatial_sampling_method=spatial_sampling,
particle_definition=particle_definition,
Expand Down Expand Up @@ -360,12 +372,9 @@ def display_calculation_result(self, scattering_result: ScatteringOutput):
""" Update graphs and select tab"""

# Plot
self.samplingCanvas.data = scattering_result
self.rdfCanvas.data = scattering_result
self.correlationCanvas.data = scattering_result
self.outputCanvas.data = scattering_result

self.tabWidget.setCurrentIndex(7) # Move to output tab if complete
self.tabWidget.setCurrentIndex(5) # Move to output tab if complete
def onFit(self):
""" Fit functionality requested"""
pass
Expand Down
14 changes: 9 additions & 5 deletions src/sas/qtgui/Perspectives/ParticleEditor/Plots/QCanvas.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from __future__ import annotations

import numpy as np
from typing import Optional

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

from sas.qtgui.Perspectives.ParticleEditor.datamodel.calculation import ScatteringOutput

import numpy as np
def spherical_form_factor(q, r):
rq = r * q
f = (np.sin(rq) - rq * np.cos(rq)) / (rq ** 3)
Expand All @@ -31,12 +32,14 @@ def data(self):
@data.setter
def data(self, scattering_output: ScatteringOutput):

# print("Setting QPlot Data")

self._data = scattering_output
self.axes.cla()


if self._data.q_space is not None:
plot_data = scattering_output.q_space.q_space_data
# print(self._data.q_space)
plot_data = self._data.q_space

q_sample = plot_data.abscissa
q_values = q_sample()
Expand All @@ -52,8 +55,9 @@ def data(self, scattering_output: ScatteringOutput):
# self.axes.axvline(0.30)

# For comparisons: TODO: REMOVE
thing = spherical_form_factor(q_values, 50)
self.axes.loglog(q_values, thing*np.max(i_values)/np.max(thing))
# thing = spherical_form_factor(q_values, 50)
# self.axes.loglog(q_values, thing*np.max(i_values)/np.max(thing))
# It works, NICE!
else:
self.axes.semilogy(q_values, i_values)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<string/>
</property>
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="definitionTab">
<attribute name="title">
Expand Down Expand Up @@ -209,7 +209,7 @@
<item row="8" column="3">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Ang</string>
<string>Ang&lt;sup&gt;-1&lt;/sup&gt;</string>
</property>
</widget>
</item>
Expand All @@ -232,7 +232,7 @@
<item row="10" column="2">
<widget class="QCheckBox" name="useLogQ">
<property name="text">
<string>Logaritmic (applies only to 1D)</string>
<string>Logaritmic</string>
</property>
<property name="checked">
<bool>true</bool>
Expand Down Expand Up @@ -436,7 +436,7 @@
<item row="7" column="3">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Ang</string>
<string>Ang&lt;sup&gt;-1&lt;/sup&gt;</string>
</property>
</widget>
</item>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time

from sas.qtgui.Perspectives.ParticleEditor.datamodel.calculation import ScatteringCalculation, ScatteringOutput
from sas.qtgui.Perspectives.ParticleEditor.datamodel.calculation import \
ScatteringCalculation, QSpaceScattering, ScatteringOutput
from sas.qtgui.Perspectives.ParticleEditor.calculations.fq import scattering_via_fq
from sas.qtgui.Perspectives.ParticleEditor.calculations.boundary_check import (
check_sld_continuity_at_boundary, check_mag_zero_at_boundary)
Expand Down Expand Up @@ -40,8 +41,10 @@ def calculate_scattering(calculation: ScatteringCalculation) -> ScatteringOutput
q_sample=q_dist,
angular_distribution=angular_dist)

q_data = QSpaceScattering(q_dist, scattering)

output = ScatteringOutput(
q_space=scattering,
q_space=q_data,
calculation_time=time.time() - start_time,
seed_used=None)

Expand Down
12 changes: 5 additions & 7 deletions src/sas/qtgui/Perspectives/ParticleEditor/calculations/fq.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
from scipy.spatial.distance import cdist

from sas.qtgui.Perspectives.ParticleEditor.datamodel.calculation import (
ScatteringCalculation, ScatteringOutput, SamplingDistribution,
QSpaceScattering, QSpaceCalcDatum, RealSpaceScattering,
SLDDefinition, MagnetismDefinition, AngularDistribution, QSample, CalculationParameters)

from sas.qtgui.Perspectives.ParticleEditor.sampling.chunking import SingleChunk, pairwise_chunk_iterator
Expand All @@ -28,27 +26,27 @@ def scattering_via_fq(
q_magnitudes = q_sample()

direction_vectors, direction_weights = angular_distribution.sample_points_and_weights()
fq = np.zeros((angular_distribution.n_points, q_sample.n_points)) # Dictionary for fq for all angles
fq = np.zeros((angular_distribution.n_points, q_sample.n_points), dtype=complex) # Dictionary for fq for all angles

for x, y, z in PointGeneratorStepper(point_generator, chunk_size):

sld = run_sld(sld_definition, parameters, x, y, z)
sld = run_sld(sld_definition, parameters, x, y, z).reshape(-1, 1)

# TODO: Magnetism

for direction_index, direction_vector in enumerate(direction_vectors):

r = np.sqrt(x*direction_vector[0] + y*direction_vector[1] + z*direction_vectors[2])
projected_distance = x*direction_vector[0] + y*direction_vector[1] + z*direction_vector[2]

i_r_dot_q = np.multiply.outer(r, 1j*q_magnitudes)
i_r_dot_q = np.multiply.outer(projected_distance, 1j*q_magnitudes)

if direction_index in fq:
fq[direction_index, :] = np.sum(sld*np.exp(i_r_dot_q), axis=0)
else:
fq[direction_index, :] += np.sum(sld*np.exp(i_r_dot_q), axis=0)

f_squared = fq.real**2 + fq.imag**2
f_squared *= direction_weights
f_squared *= direction_weights.reshape(-1,1)

return np.sum(f_squared, axis=0)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ def generate(self, start_index: int, end_index: int) -> VectorComponents3:
""" Generate points from start_index up to end_index """

@abstractmethod
def bounding_surface_check_points(self) -> VectorComponents3:
def _bounding_surface_check_points(self) -> np.ndarray:
""" Points used to check that the SLD/magnetism vector are zero outside the sample space"""

def bounding_surface_check_points(self) -> VectorComponents3:
pts = self._bounding_surface_check_points()
return pts[:, 0], pts[:, 1], pts[:, 2]

class AngularDistribution(ABC):
""" Base class for angular distributions """

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class BoundedByCube(SpatialDistribution):
[-1,-1, 1],
[-1,-1,-1],
], dtype=float)
def bounding_surface_check_points(self) -> VectorComponents3:
def _bounding_surface_check_points(self) -> VectorComponents3:
return BoundedByCube._boundary_base_points * self.radius


Expand Down

0 comments on commit bf5f089

Please sign in to comment.