diff --git a/.gitignore b/.gitignore
index ec34863..3d72cde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,4 +47,10 @@ juno.egg-info/PKG-INFO
!mkdocs.yml
# !docs.yml
-!.github/workflows/*
\ No newline at end of file
+!.github/workflows/*
+
+# simulation generated files
+*.png
+*.json
+*.csv
+*.log
diff --git a/juno/Lens.py b/juno/Lens.py
index 783df75..f176d39 100644
--- a/juno/Lens.py
+++ b/juno/Lens.py
@@ -776,6 +776,12 @@ def calculate_escape_path_dimensions(lens: Lens, ep: float):
lens_h, lens_w = lens.profile.shape
ep_h, ep_w = int(lens_h * (1 + ep)), int(lens_w * (1 + ep))
+ # ensure the escape path is odd
+ if ep_h % 2 == 0:
+ ep_h += 1
+ if ep_w % 2 == 0:
+ ep_w += 1
+
return (ep_h, ep_w)
diff --git a/juno/_version.py b/juno/_version.py
new file mode 100644
index 0000000..649f7a6
--- /dev/null
+++ b/juno/_version.py
@@ -0,0 +1,4 @@
+# file generated by setuptools_scm
+# don't change, don't track in version control
+__version__ = version = '0.1.dev560+gefa629d.d20230301'
+__version_tuple__ = version_tuple = (0, 1, 'dev560', 'gefa629d.d20230301')
diff --git a/juno/beam.py b/juno/beam.py
index e7cb610..d4f9eb6 100644
--- a/juno/beam.py
+++ b/juno/beam.py
@@ -381,6 +381,11 @@ def validate_beam_configuration(settings: BeamSettings):
if settings.source_distance is None:
raise ValueError(f"A source_distance must be provided for {settings.distance_mode}")
+ # check if step size greater than propagation distance
+ if settings.step_size is not None:
+ if settings.step_size > settings.source_distance:
+ raise ValueError(f"The step_size ({settings.step_size:.2e}m) must be less than the source_distance ({settings.source_distance:.2e}m) for {settings.distance_mode}.")
+
if settings.distance_mode == DistanceMode.Focal:
if settings.beam_spread not in [BeamSpread.Converging, BeamSpread.Diverging]:
raise ValueError(f"BeamSpread must be Converging, or Diverging for {settings.distance_mode} (currently {settings.beam_spread})")
diff --git a/juno/juno_custom/README.md b/juno/juno_custom/README.md
new file mode 100644
index 0000000..f3d31b4
--- /dev/null
+++ b/juno/juno_custom/README.md
@@ -0,0 +1,4 @@
+# README
+
+
+The tools in this directory are experimental and are not supported by the Juno team. They are provided as-is and are not guaranteed to work. If you find a bug, please report it on Github
\ No newline at end of file
diff --git a/juno/juno_custom/__init__.py b/juno/juno_custom/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/juno/juno_custom/element_template.py b/juno/juno_custom/element_template.py
new file mode 100644
index 0000000..22248bb
--- /dev/null
+++ b/juno/juno_custom/element_template.py
@@ -0,0 +1,25 @@
+from abc import ABC, abstractmethod
+
+from juno import Lens
+
+
+class ElementTemplate(ABC):
+ def __init__(self) -> None:
+ pass
+
+ def __repr__(self) -> str:
+ return f"Custom Element: {self.name}"
+
+ @abstractmethod
+ def generate_profile(self):
+ raise NotImplementedError("Custom elements must be modified in some way.")
+
+ def analyse(self):
+ print("No analysis conducted.")
+
+ @staticmethod
+ @abstractmethod
+ def __keys__() -> dict:
+ raise NotImplementedError(
+ "Custom elements must have a list of keys to generate a profile."
+ )
diff --git a/juno/juno_custom/elements/__init__.py b/juno/juno_custom/elements/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/juno/juno_custom/elements/axicon.py b/juno/juno_custom/elements/axicon.py
new file mode 100644
index 0000000..d2d31e7
--- /dev/null
+++ b/juno/juno_custom/elements/axicon.py
@@ -0,0 +1,26 @@
+# from juno.Lens import Lens
+
+# from juno_custom.element_template import ElementTemplate
+
+
+# AXICON_KEYS = ["height", "width", "exponent", "coefficient", "pixel_size"]
+
+# class Axicon(ElementTemplate):
+# def __init__(self, lens: Lens) -> None:
+# super().__init__(lens)
+# self.name = "Axicon"
+
+# def __identifier__(self) -> str:
+# return f"""Axicon"""
+
+# def __repr__(self) -> str:
+# return f"""Axicon (Exponent = 1.0)"""
+
+# def generate_profile(self):
+# self.lens.exponent = 1
+
+# def analyse(self):
+# print("Axicon analysis.")
+
+# def __keys__(self) -> list:
+# return AXICON_KEYS
\ No newline at end of file
diff --git a/juno/juno_custom/elements/focusing.py b/juno/juno_custom/elements/focusing.py
new file mode 100644
index 0000000..d42cc7b
--- /dev/null
+++ b/juno/juno_custom/elements/focusing.py
@@ -0,0 +1,21 @@
+# from juno_custom.element_template import ElementTemplate
+# from juno.Lens import Lens
+
+# FOCUSING_KEYS = ["height", "width", "exponent", "coefficient", "pixel_size"]
+
+# class FocusingLens(ElementTemplate):
+# def __init__(self, lens: Lens) -> None:
+# super().__init__(lens)
+# self.name = "Focusing"
+
+# def __repr__(self) -> str:
+# return f"""Focusing Lens (Exponent = 2.0)"""
+
+# def generate_profile(self):
+# self.lens.exponent = 2
+
+# def analyse(self):
+# print("Focusing")
+
+# def __keys__(self) -> list:
+# return FOCUSING_KEYS
diff --git a/juno/juno_custom/elements/lattice.py b/juno/juno_custom/elements/lattice.py
new file mode 100644
index 0000000..3fd5ce0
--- /dev/null
+++ b/juno/juno_custom/elements/lattice.py
@@ -0,0 +1,378 @@
+import numpy as np
+from juno import utils as j_utils
+from juno.Lens import Lens
+from scipy import ndimage
+
+from juno_custom.element_template import ElementTemplate
+import numpy as np
+import matplotlib.pyplot as plt
+from numpy.fft import fft2, ifftshift, fftshift
+from scipy.interpolate import RectBivariateSpline, RegularGridInterpolator
+from scipy.ndimage import interpolation
+import os
+import sys
+from PIL import Image
+
+from numba import jit
+
+# name: [type, default, critical, fixed, description]
+LATTICE_KEYS = {
+ "wave": [float, 0.488, True, False, "Wavelength of light in um"],
+ "NA_inner": [float, 0.42, True, False, "Inner NA of the mask aperture"],
+ "NA_outer": [float, 0.6, True, False, "Outer NA of the mask aperture"],
+ "spacing": [float, 0.97, True, False, "Spacing between the beams"],
+ "n_beam": [int, 46, True, False, "Number of beams"],
+ "crop": [float, 0.22, True, True, "Crop factor"],
+ "tilt": [float, 0, True, False, "Tilt of the pattern"],
+ "shift_x": [float, 0, True, False, "Shift of the pattern in x direction"],
+ "shift_y": [float, 0, True, False, "Shift of the pattern in y direction"],
+ "mag": [float, 167.364, True, False, "Magnification between SLM mask and sample"],
+ "pixel": [float, 13.62, True, False, "Pixel size of the element in um"],
+ "slm_xpix": [int, 1280, True, False, "Number of pixels in x direction"],
+ "slm_ypix": [int, 1024, True, False, "Number of pixels in y direction"],
+ "mode": [str, "binary", True, False, "Mode of the pattern (binary, pupil, intensity)"],
+}
+
+
+class Lattice(ElementTemplate):
+ def __init__(self) -> None:
+ super().__init__()
+ self.name = "Lattice"
+
+ def __repr__(self) -> str:
+ return f"""Lattice Profile"""
+
+ def generate_profile(self, params):
+ self.profile = linear_bessel_array(
+ show=False,
+ outdir=None,
+ pattern_only=True,
+ test=False,
+ save=False,
+ savefig=False,
+ path=None,
+ **params,
+ )
+
+ @staticmethod
+ def __keys__() -> dict:
+ return LATTICE_KEYS
+
+
+def linear_bessel_array(
+ wave=0.488,
+ NA_inner=0.44,
+ NA_outer=0.55,
+ spacing=None,
+ n_beam="fill",
+ crop=0.22,
+ tilt=0,
+ shift_x=0,
+ shift_y=0,
+ mag=167.364,
+ pixel=13.662,
+ slm_xpix=1280,
+ slm_ypix=1024,
+ fillchip=0.95,
+ fudge=0.95,
+ show=False,
+ outdir=None,
+ pattern_only=True,
+ test=False,
+ save=False,
+ savefig=False,
+ mode="binary",
+ path=None,
+):
+
+ if path:
+ if save or savefig:
+ if not os.path.exists(path):
+ os.makedirs(path, exist_ok=True)
+
+ # auto-choose good spacing
+ if not spacing:
+ spacing = fudge * wave / NA_inner
+
+ # to fill the chip
+ if n_beam == "fill" and fillchip:
+ n_beam = int(
+ np.floor(1 + ((fillchip * (slm_xpix * (pixel / mag) / 2)) / spacing))
+ )
+
+ # Populate real space array
+ dx = pixel / mag
+ x = np.arange(-(slm_xpix) / 2, (slm_xpix + 1) / 2, 1.0) * dx
+ y = x
+
+ # for scipy interpolation functions, we don't use the meshgrid...
+ x_slm = np.linspace(x[0], x[-1], slm_xpix)
+ y_slm = x_slm
+
+ # Populate k space array
+ dk = 2 * np.pi / (slm_xpix + 1) / dx
+ kx = np.arange(-(slm_xpix) / 2, (slm_xpix + 1) / 2, 1.0) * dk
+ ky = kx
+ [kx, ky] = np.meshgrid(kx, ky)
+ kr = np.sqrt(kx * kx + ky * ky)
+
+ # Mask k-space array according to inner and outer NA
+ pupil_mask = (kr < NA_outer * (2 * np.pi / wave)) & (
+ kr > NA_inner * (2 * np.pi / wave)
+ )
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "pupil_mask"), pupil_mask)
+ if savefig:
+ plt.figure()
+ plt.imshow(pupil_mask)
+ plt.title("Pupil mask")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "pupil_mask.png"))
+
+ # Generate array of bessel beams by applying phase ramps in k-space
+ pupil_field_ideal = pupil_mask.astype(np.complex128)
+
+ f = kx * spacing * np.cos(tilt) + ky * spacing * np.sin(tilt)
+
+ @jit(nopython=True)
+ def calc(v, ii):
+ A = np.exp(1j * f * ii) + np.exp(-1j * f * ii)
+ return v + np.multiply(pupil_mask, A)
+
+ for ii in range(1, n_beam):
+ pupil_field_ideal = calc(pupil_field_ideal, ii)
+ pupil_field_ideal *= np.exp(1j * (kx * shift_x + ky * shift_y))
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "pupil_field_ideal"), pupil_field_ideal)
+ if savefig:
+ plt.figure()
+ plt.imshow(np.abs(pupil_field_ideal))
+ plt.title("Pupil field ideal")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "pupil_field_ideal.png"))
+
+ # Ideal SLM field of fourier transform of pupil field
+ slm_field_ideal = fftshift(fft2(ifftshift(pupil_field_ideal))).real
+ slm_field_ideal /= np.max(np.max(np.abs(slm_field_ideal)))
+
+ # TODO: Save ideal slm field
+ ideal = np.abs(slm_field_ideal * slm_field_ideal)
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "ideal"), ideal)
+ if savefig:
+ plt.figure()
+ plt.imshow(ideal)
+ plt.title("Ideal coherent bessel light sheet intensity")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "ideal.png"))
+
+ # Display ideal intensity at sample (incorporates supersampling)
+ if show:
+ plt.figure()
+ plt.imshow(np.abs(slm_field_ideal * slm_field_ideal))
+ plt.title("Ideal coherent bessel light sheet intensity")
+ plt.axis("image")
+ plt.colorbar()
+
+ # Interpolate back onto SLM pixels and apply cropping factor
+ # interpolator = interp2d(x, x, slm_field_ideal)
+ interpolator = RectBivariateSpline(x, y, slm_field_ideal)
+ slm_pattern = interpolator(x_slm, y_slm)
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "slm_pattern"), slm_pattern)
+ if savefig:
+ plt.figure()
+ plt.imshow(slm_pattern)
+ plt.title("SLM pattern")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "slm_pattern.png"))
+
+ # slm_pattern *= np.abs(slm_pattern) > crop
+ slm_pattern[np.abs(slm_pattern) < crop] = 0
+ eps = np.finfo(float).eps
+ slm_pattern = np.sign(slm_pattern + eps) * np.pi / 2 + np.pi / 2
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "slm_pattern_binary"), slm_pattern)
+ if savefig:
+ plt.figure()
+ plt.imshow(slm_pattern)
+ plt.title("SLM pattern binarised")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "slm_pattern_binary.png"))
+
+ # Account for rectangular aspect ratio of SLM and convert phase to binary
+ low = int(np.floor((slm_xpix / 2) - (slm_ypix / 2) - 1))
+ high = int(low + slm_ypix)
+ slm_pattern_final = (slm_pattern[low:high, :] / np.pi) != 0
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "slm_pattern_binary_2"), slm_pattern_final)
+ if savefig:
+ plt.figure()
+ plt.imshow(slm_pattern_final)
+ plt.title("SLM pattern binary 2")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "slm_pattern_binary_2.png"))
+
+ if outdir is not None:
+ outdir = os.path.abspath(os.path.expanduser(outdir))
+ if os.path.isdir(outdir):
+ namefmt = (
+ "{:.0f}_{:2d}b_s{:.2f}_c{:.2f}_na{:.0f}-{:.0f}_x{:02f}_y{:02f}_t{:0.3f}"
+ )
+ name = namefmt.format(
+ wave * 1000,
+ n_beam * 2 - 1,
+ spacing,
+ crop,
+ 100 * NA_outer,
+ 100 * NA_inner,
+ shift_x,
+ shift_y,
+ tilt,
+ )
+ name = name.replace(".", "p")
+ outpath = os.path.join(outdir, name + ".png")
+
+ imout = Image.fromarray(slm_pattern_final.astype(np.uint8) * 255)
+ imout = imout.convert("1")
+ imout.save(outpath)
+
+ if show:
+ plt.figure()
+ plt.imshow(slm_pattern, interpolation="nearest")
+ plt.title(
+ "Cropped and pixelated phase from SLM pattern exiting the polarizing beam splitter"
+ )
+ plt.axis("image")
+
+ plt.figure()
+ plt.imshow(slm_pattern_final, interpolation="nearest", cmap="gray")
+ plt.title("Binarized image to output to SLM")
+
+ # if pattern_only:
+ # print(f'Mode: {mode}')
+ # if mode == 'binary':
+ # return slm_pattern_final #, intensity_final, pupil_field
+ # elif mode == 'pupil':
+ # return pupil_field
+ # elif mode == 'intensity':
+ # return intensity_final
+ # if show:
+ # plt.show()
+ # return slm_pattern_final
+
+ # this method uses nearest neighbor like the matlab version
+ [xmesh, ymesh] = np.meshgrid(x, y)
+ coords = np.array([xmesh.flatten(), ymesh.flatten()]).T
+ interpolator = RegularGridInterpolator(
+ (x_slm, y_slm), slm_pattern, method="nearest"
+ )
+ slm_pattern_cal = interpolator(coords) # supposed to be nearest neighbor
+ slm_pattern_cal = slm_pattern_cal.reshape(len(x), len(y)).T
+ slm_field = np.exp(1j * slm_pattern_cal)
+
+ # at this point, matlab has complex component = 0.0i
+
+ # Compute intensity impinging on annular mask
+ pupil_field_impinging = fftshift(fft2(ifftshift(slm_field)))
+ pupil_field_impinging_real = np.real(
+ pupil_field_impinging * np.conj(pupil_field_impinging)
+ )
+ if path:
+ if save:
+ np.save(
+ os.path.join(path, "pupil_field_impinging_real"),
+ pupil_field_impinging_real,
+ )
+ if savefig:
+ plt.figure()
+ plt.imshow(pupil_field_impinging_real)
+ plt.title("Real component of impinging pupil field")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "pupil_field_impinging_real.png"))
+
+ # Compute intensity passing through annular mask
+ pupil_field = pupil_field_impinging * pupil_mask
+ pupil_field_real = np.real(pupil_field * np.conj(pupil_field))
+ if path:
+ if save:
+ np.save(os.path.join(path, "pupil_field_real"), pupil_field_real)
+ if savefig:
+ plt.figure()
+ plt.imshow(pupil_field_real)
+ plt.title("Real part of pupil field")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "pupil_field_real.png"))
+
+ if show:
+ plt.figure()
+ ax1 = plt.subplot(1, 2, 1)
+ plt.imshow(
+ (pupil_field_impinging * np.conj(pupil_field_impinging)).real,
+ interpolation="nearest",
+ cmap="inferno",
+ )
+ plt.clim(0, (2 * n_beam - 1) * 3e6)
+ plt.title("Intensity impinging on annular mask")
+ plt.subplot(1, 2, 2, sharex=ax1)
+ plt.imshow(
+ (pupil_field * np.conj(pupil_field)).real,
+ interpolation="nearest",
+ cmap="inferno",
+ )
+ plt.clim(0, (2 * n_beam - 1) * 3e6)
+ plt.title("Intensity after annular mask")
+
+ # Compute intensity at sample
+ field_final = fftshift(fft2(ifftshift(pupil_field)))
+ intensity_final = (field_final * np.conj(field_final)).real
+
+ if path:
+ if save:
+ np.save(os.path.join(path, "sample_intensity"), intensity_final)
+ if savefig:
+ plt.figure()
+ plt.imshow(intensity_final)
+ plt.title("Sample Intensity")
+ plt.axis("image")
+ plt.colorbar()
+ plt.savefig(os.path.join(path, "sample_intensity.png"))
+
+ if show:
+ plt.figure()
+ plt.imshow(intensity_final, interpolation="nearest")
+ plt.title("Actual intensity at sample")
+ plt.axis("image")
+ plt.show()
+
+ plt.close("all")
+ if test:
+ return pupil_field, slm_pattern_final, intensity_final
+
+ # print(f"Mode: {mode}")
+ if mode == "binary":
+ return slm_pattern_final # , intensity_final, pupil_field
+ elif mode == "pupil":
+ return pupil_field_real
+ elif mode == "intensity":
+ return intensity_final
diff --git a/juno/juno_custom/elements/microlens.py b/juno/juno_custom/elements/microlens.py
new file mode 100644
index 0000000..ec87bb4
--- /dev/null
+++ b/juno/juno_custom/elements/microlens.py
@@ -0,0 +1,51 @@
+import numpy as np
+from juno import utils as j_utils
+from juno.Lens import Lens
+from scipy import ndimage
+
+from juno_custom.element_template import ElementTemplate
+
+EXTENDED_KEYS = {
+ "pixel_size": [float, 1.e-6, True, False, "Pixel size of the element in m"],
+ "diameter": [float, 100.e-6, True, False, "Diameter of the element in m"],
+ "coefficient": [float, 10000, True, False, "Coefficient of the element"],
+ "escape_path": [float, 0.1, True, False, "Percentage of escape path"],
+ "exponent": [float, 2.3, True, False, "Exponent of the element"],
+}
+
+
+class ExtendedMicrolens(ElementTemplate):
+ def __init__(self) -> None:
+ super().__init__()
+ self.name = "ExtendedMicrolens"
+
+ def __repr__(self) -> str:
+ return f"""Extended Microlens"""
+
+ def generate_profile(self, params):
+ self.profile = generate_lens(
+ **params
+ )
+
+ def analyse(self):
+ print("Extended microlens capability")
+
+ @staticmethod
+ def __keys__() -> list:
+ return EXTENDED_KEYS
+
+
+def generate_lens(pixel_size, diameter, coefficient, escape_path, exponent):
+ n_pixels = j_utils._calculate_num_of_pixels(diameter, pixel_size)
+ radius = diameter / 2
+ n_pixels_in_radius = n_pixels // 2 + 1
+ radius_px = np.linspace(0, radius, n_pixels_in_radius)
+ profile = -coefficient * radius_px**exponent
+ profile -= np.min(profile)
+ profile = np.append(profile, np.zeros(int(escape_path * len(profile))))
+ profile = np.append(np.flip(profile[1:]), profile)
+ profile = ndimage.gaussian_filter(profile, sigma=3)
+ profile = np.expand_dims(profile, 0).astype(np.float32)
+
+ return profile
+
\ No newline at end of file
diff --git a/juno/juno_custom/elements/template.py b/juno/juno_custom/elements/template.py
new file mode 100644
index 0000000..c95656c
--- /dev/null
+++ b/juno/juno_custom/elements/template.py
@@ -0,0 +1,23 @@
+from juno.Lens import Lens
+
+from element_template import ElementTemplate
+
+KEYS = []
+
+
+class CustomLens(ElementTemplate):
+ def __init__(self, lens: Lens) -> None:
+ super().__init__(lens)
+ self.name = "CustomLens"
+
+ def __repr__(self) -> str:
+ return f"""Custom Lens"""
+
+ def generate_profile(self):
+ pass
+
+ def analyse(self):
+ print("Custom analysis.")
+
+ def __keys__(self) -> list:
+ return KEYS
diff --git a/juno/juno_custom/elements/test.py b/juno/juno_custom/elements/test.py
new file mode 100644
index 0000000..530933f
--- /dev/null
+++ b/juno/juno_custom/elements/test.py
@@ -0,0 +1,38 @@
+import numpy as np
+from juno import utils as j_utils
+from juno.Lens import Lens
+from scipy import ndimage
+
+from juno_custom.element_template import ElementTemplate
+
+TEST_KEYS = {
+ "pixel_size": [float, 1.e-6, True, False, "Pixel Size"],
+ "diameter": [float, 0.42, True, False, "Diameter of the element"],
+ "coefficient": [float, 0.5, True, False, "Coefficient of the element"],
+ "escape_path": [float, 0.97, True, False, "Percentage of escape path"],
+ "exponent": [int, 46, True, False, "Exponent of the element"],
+}
+
+class TestLens(ElementTemplate):
+ def __init__(self) -> None:
+ super().__init__()
+ self.name = "Test"
+
+ def __repr__(self) -> str:
+ return f"""Test"""
+
+ def generate_profile(self, params):
+ self.profile = generate_element(**params)
+
+ def analyse(self):
+ print("Test analysis")
+
+ @staticmethod
+ def __keys__() -> list:
+ return TEST_KEYS
+
+
+def generate_element(pixel_size, diameter, coefficient, escape_path, exponent):
+ profile = np.zeros((1000, 1000))
+ profile[450:550, 450:550] = 1
+ return profile
\ No newline at end of file
diff --git a/juno/juno_custom/main.py b/juno/juno_custom/main.py
new file mode 100644
index 0000000..2c407b4
--- /dev/null
+++ b/juno/juno_custom/main.py
@@ -0,0 +1,80 @@
+import os
+import sys
+from pprint import pprint
+from juno import utils as j_utils
+import itertools
+from juno_custom.tools import element_tools, simulation_tools, beam_tools
+
+package_path = os.path.dirname(os.path.abspath(__file__))
+
+MODES = ["simulation", "element"]
+
+def main(config_filename=None):
+ if config_filename is None:
+ raise ValueError("Config file must be provided.")
+
+ # load config and append the system information
+ config = j_utils.load_yaml_config(config_filename=config_filename)
+
+ if config.get("mode") is None:
+ raise ValueError("Mode must be provided.")
+
+ if config.get("mode") not in MODES:
+ raise ValueError("Mode must be one of the following: {}".format(MODES))
+
+ system_config = simulation_tools.load_system_config(config=config, system_config_path="system_config.yaml")
+ config["system"] = system_config
+
+
+ if config.get("mode") == "simulation":
+ key_list = []
+ config["lenses"] = []
+ for i, element in enumerate(config["elements"]):
+ element_config = j_utils.load_yaml_config(config_filename=element["path"])
+ config["lenses"].append({"name": element["name"]})
+ for key, value in element_config.items():
+ config["lenses"][i][key] = value
+
+ if "keys" in config["lenses"][i]:
+ key_list.append(config["lenses"][i]["keys"])
+
+ key_list = list(itertools.chain(*key_list))
+
+ if len(key_list) > 0:
+ simulation_tools.iterate_through_parameter_combinations(config=config, key_list=key_list)
+
+ pprint(config)
+ pprint(key_list)
+ return
+
+ if not (
+ "keys" in config
+ and config["keys"] is not None
+ and isinstance(config["keys"], list)
+ ):
+ run(config=config)
+
+ elif len(config["keys"]) > 0:
+ simulation_tools.iterate_through_parameter_combinations(config=config)
+
+def run(config: dict, count=0):
+
+ if config.get("mode") == "simulation":
+ for element in config["elements"]:
+
+
+
+ config = beam_tools.generate_beam_config(config=config)
+ config = simulation_tools.generate_simulation_config(config=config)
+
+
+ element = element_tools.generate_element(config=config)
+ element.generate_profile()
+
+ simulation_tools.save_outputs(config=config, profile=element.profile, count=count)
+
+if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ main(sys.argv[1])
+ else:
+ raise ValueError("Config file must be provided.")
diff --git a/juno/juno_custom/system_config.yaml b/juno/juno_custom/system_config.yaml
new file mode 100644
index 0000000..0e48d1b
--- /dev/null
+++ b/juno/juno_custom/system_config.yaml
@@ -0,0 +1,6 @@
+linux: /home/dadie1/zt14/David/
+windows: C:/Users/User/Github/
+
+creation_config_path: ""
+juno_path: juno/juno/
+juno_custom_path: juno_custom/juno_custom/
diff --git a/juno/juno_custom/tools/beam_tools.py b/juno/juno_custom/tools/beam_tools.py
new file mode 100644
index 0000000..f11cc67
--- /dev/null
+++ b/juno/juno_custom/tools/beam_tools.py
@@ -0,0 +1,41 @@
+import itertools
+import os
+import sys
+import numpy as np
+
+import utils
+import yaml
+from juno import SimulationRunner, validation
+from copy import deepcopy
+
+from juno_custom.tools import element_tools
+from juno import utils as j_utils
+
+def generate_beam_config(config: dict):
+ if config.get("beam") is None or config["beam"].get("match"):
+ config = match_beam(config=config)
+
+ return config
+
+
+def match_beam(config: dict):
+ # TODO: check for spherical here?
+ beam_config = deepcopy(config.get("beam"))
+ beam_config["beam_type"] = config.get("beam_type")
+ beam_config["height"] = config.get("length")
+ beam_config["width"] = config.get("diameter")
+ beam_config["distance_mode"] = "Direct"
+ beam_config["source_distance"] = 1.e-9
+ beam_config["n_steps"] = 2
+ beam_config["numerical_aperture"] = 0.0
+ beam_config["position_x"] = 0.0
+ beam_config["position_y"] = 0.0
+ beam_config["shape"] = config.get("lens_type")
+ beam_config["spread"] = "Plane"
+ beam_config["step_size"] = 0.0
+ beam_config["tilt_x"] = 0.0
+ beam_config["tilt_y"] = 0.0
+ beam_config["theta"] = 0.0
+
+ config["beam"] = beam_config
+ return config
diff --git a/juno/juno_custom/tools/element_tools.py b/juno/juno_custom/tools/element_tools.py
new file mode 100644
index 0000000..9b38c05
--- /dev/null
+++ b/juno/juno_custom/tools/element_tools.py
@@ -0,0 +1,74 @@
+import glob
+import importlib
+import os
+
+from juno.Lens import Lens
+from juno.Medium import Medium
+
+import juno_custom.elements
+from juno_custom.element_template import ElementTemplate
+
+# These are the modules that will be ignored when importing custom lenses
+IGNORED_MODULES = ["__init__", "template"]
+
+
+def import_custom_elements():
+ # get all the modules in the custom_lenses folder
+ module_names = [
+ os.path.basename(f)[:-3]
+ for f in glob.glob(os.path.join(juno_custom.elements.__path__[0], "*.py"))
+ ]
+
+ # iterate through the modules, removing any that have a substring in IGNORED_MODULES
+ module_names = [
+ juno_custom.elements.__name__ + "." + module
+ for module in module_names
+ if not any([a in module for a in IGNORED_MODULES])
+ ]
+
+ # iterate through the modules and try to import them
+ for module_ in module_names:
+ try:
+ importlib.import_module(module_)
+
+ except Exception as e:
+ print(f"Failed to import {module_}, reason being: {e}")
+
+
+def get_custom_elements():
+ import_custom_elements()
+ return ElementTemplate.__subclasses__()
+
+
+def generate_base_element(config: dict):
+ diameter = config.get("diameter")
+ height = config.get("height")
+ medium = config.get("medium")
+ exponent = config.get("exponent")
+ base_element = Lens(diameter, height, exponent, Medium(medium))
+ base_element.generate_profile(config.get("pixel_size"))
+ return base_element
+
+
+def generate_element(config: dict):
+ base_element = generate_base_element(config=config)
+ element = ElementFactory.create_element(
+ element_type=config.get("element_type"), lens=base_element
+ )
+ return element
+
+
+def generate_element_config(config: dict):
+ config["lenses"] = {}
+
+
+class ElementFactory:
+ @staticmethod
+ def create_element(element_type: str = None, lens: Lens = None):
+ if element_type is None:
+ raise ValueError("Element type must be provided.")
+
+ for custom_element in get_custom_elements():
+ if element_type.lower() == custom_element.__name__.lower():
+ return custom_element(lens)
+ raise ValueError(f"Element type {element_type} not found.")
diff --git a/juno/juno_custom/tools/simulation_tools.py b/juno/juno_custom/tools/simulation_tools.py
new file mode 100644
index 0000000..44815b9
--- /dev/null
+++ b/juno/juno_custom/tools/simulation_tools.py
@@ -0,0 +1,104 @@
+import itertools
+import os
+import sys
+import numpy as np
+
+import utils
+import yaml
+from juno import SimulationRunner, validation
+
+from juno_custom.tools import element_tools, beam_tools
+from juno_custom import main
+from juno import utils as j_utils
+from copy import deepcopy
+
+
+def get_parameter_combinations(config: dict, key_list: list):
+ sweep_keys = key_list
+ config = validation._validate_sweepable_parameters(config, sweep_keys)
+ kp = SimulationRunner.sweep_config_keys(config, sweep_keys)
+ param_combos = list(itertools.product(*kp))
+ print(param_combos)
+ return param_combos
+
+
+def iterate_through_parameter_combinations(config: dict, key_list: list):
+ param_combos = get_parameter_combinations(config=config, key_list=key_list)
+ # for i, param_combo in enumerate(param_combos):
+ # for j, key in enumerate(config["keys"]):
+ # if isinstance(param_combo[j], float):
+ # config[key] = float(param_combo[j])
+ # elif isinstance(param_combo[j], str):
+ # config[key] = str(param_combo[j])
+
+ # main.run(config=config, count=i)
+
+
+def save_outputs(config: dict, profile: np.ndarray, count=0):
+ save_config(
+ config,
+ os.path.join(
+ config["system"].get("configs_path"), "config_" + str(count) + ".yaml"
+ ),
+ )
+ save_profile(
+ profile=profile,
+ filename=os.path.join(
+ config["system"].get("configs_path"), "profile_" + str(count)
+ ),
+ )
+
+
+def generate_simulation_config(config: dict):
+ if config.get("simulation_name") is None or config["sim_parameters"].get("match"):
+ config = match_simulation(config=config)
+ config["sim_parameters"]["pixel_size"] = config.get("pixel_size")
+ return config
+
+
+def match_simulation(config: dict):
+ sim_config = deepcopy(config["sim_parameters"])
+ # TODO: check for spherical here?
+ sim_config["sim_height"] = config.get("length")
+ sim_config["sim_width"] = config.get("diameter")
+
+ config["sim_parameters"] = sim_config
+
+ return config
+
+
+def save_config(config: dict, filename: str):
+ if not os.path.exists(os.path.dirname(filename)):
+ os.makedirs(os.path.dirname(filename))
+ with open(filename, "w") as f:
+ yaml.safe_dump(config, f, sort_keys=False)
+
+
+def save_profile(profile: dict, filename: str):
+ np.save(filename, profile)
+
+
+def load_system_config(config: dict, system_config_path: str = None):
+
+ if system_config_path is None:
+ raise ValueError("System config path must be provided.")
+
+ system_config = j_utils.load_yaml_config(config_filename=system_config_path)
+
+ if sys.platform == "win32":
+ base_path = system_config.get("windows")
+ elif sys.platform == "linux":
+ base_path = system_config.get("linux")
+ else:
+ raise ValueError("Unknown operating system.")
+
+ system_config["base_path"] = base_path
+
+ system_config["configs_path"] = os.path.join(
+ system_config.get("base_path"),
+ system_config.get("juno_custom_path"),
+ "simulations",
+ config.get("directory_name"),
+ "configs",
+ )
+ return system_config
diff --git a/juno/juno_custom/ui/__init__.py b/juno/juno_custom/ui/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/juno/juno_custom/ui/main.py b/juno/juno_custom/ui/main.py
new file mode 100644
index 0000000..e7d193b
--- /dev/null
+++ b/juno/juno_custom/ui/main.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'main.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.7
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(316, 722)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
+ self.gridLayout.setObjectName("gridLayout")
+ self.frameMainWindow = QtWidgets.QFrame(self.centralwidget)
+ self.frameMainWindow.setFrameShape(QtWidgets.QFrame.StyledPanel)
+ self.frameMainWindow.setFrameShadow(QtWidgets.QFrame.Raised)
+ self.frameMainWindow.setObjectName("frameMainWindow")
+ self.gridLayout_2 = QtWidgets.QGridLayout(self.frameMainWindow)
+ self.gridLayout_2.setObjectName("gridLayout_2")
+ self.frame_Options = QtWidgets.QFrame(self.frameMainWindow)
+ self.frame_Options.setFrameShape(QtWidgets.QFrame.StyledPanel)
+ self.frame_Options.setFrameShadow(QtWidgets.QFrame.Raised)
+ self.frame_Options.setObjectName("frame_Options")
+ self.gridLayout_2.addWidget(self.frame_Options, 1, 1, 1, 1)
+ spacerItem = QtWidgets.QSpacerItem(20, 800, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout_2.addItem(spacerItem, 2, 1, 2, 1)
+ self.frame_Setup = QtWidgets.QFrame(self.frameMainWindow)
+ self.frame_Setup.setMinimumSize(QtCore.QSize(0, 120))
+ self.frame_Setup.setMaximumSize(QtCore.QSize(16777215, 120))
+ self.frame_Setup.setFrameShape(QtWidgets.QFrame.StyledPanel)
+ self.frame_Setup.setFrameShadow(QtWidgets.QFrame.Raised)
+ self.frame_Setup.setObjectName("frame_Setup")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_Setup)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.comboBox_Elements = QtWidgets.QComboBox(self.frame_Setup)
+ self.comboBox_Elements.setObjectName("comboBox_Elements")
+ self.verticalLayout.addWidget(self.comboBox_Elements)
+ self.gridLayout_2.addWidget(self.frame_Setup, 0, 1, 1, 1)
+ self.frame_Save = QtWidgets.QFrame(self.frameMainWindow)
+ self.frame_Save.setFrameShape(QtWidgets.QFrame.StyledPanel)
+ self.frame_Save.setFrameShadow(QtWidgets.QFrame.Raised)
+ self.frame_Save.setObjectName("frame_Save")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_Save)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.pushButton_GenerateProfile = QtWidgets.QPushButton(self.frame_Save)
+ self.pushButton_GenerateProfile.setObjectName("pushButton_GenerateProfile")
+ self.verticalLayout_2.addWidget(self.pushButton_GenerateProfile)
+ self.pushButton_SaveProfile = QtWidgets.QPushButton(self.frame_Save)
+ self.pushButton_SaveProfile.setObjectName("pushButton_SaveProfile")
+ self.verticalLayout_2.addWidget(self.pushButton_SaveProfile)
+ self.pushButton_SaveParameters = QtWidgets.QPushButton(self.frame_Save)
+ self.pushButton_SaveParameters.setObjectName("pushButton_SaveParameters")
+ self.verticalLayout_2.addWidget(self.pushButton_SaveParameters)
+ self.gridLayout_2.addWidget(self.frame_Save, 4, 1, 1, 1)
+ self.gridLayout.addWidget(self.frameMainWindow, 0, 0, 1, 1)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 316, 21))
+ self.menubar.setObjectName("menubar")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "CustomElement :: Designer"))
+ self.pushButton_GenerateProfile.setText(_translate("MainWindow", "Generate Profile"))
+ self.pushButton_SaveProfile.setText(_translate("MainWindow", "Save Profile"))
+ self.pushButton_SaveParameters.setText(_translate("MainWindow", "Save Parameters"))
diff --git a/juno/juno_custom/ui/main.ui b/juno/juno_custom/ui/main.ui
new file mode 100644
index 0000000..9b1de8f
--- /dev/null
+++ b/juno/juno_custom/ui/main.ui
@@ -0,0 +1,129 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 316
+ 722
+
+
+
+ CustomElement :: Designer
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 800
+
+
+
+
+ -
+
+
+
+ 0
+ 120
+
+
+
+
+ 16777215
+ 120
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+ Generate Profile
+
+
+
+ -
+
+
+ Save Profile
+
+
+
+ -
+
+
+ Save Parameters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/juno/juno_custom/user_interface.py b/juno/juno_custom/user_interface.py
new file mode 100644
index 0000000..d6432ca
--- /dev/null
+++ b/juno/juno_custom/user_interface.py
@@ -0,0 +1,136 @@
+import napari
+import numpy as np
+import yaml
+from napari.qt.threading import thread_worker
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+import juno_custom.tools.element_tools as element_tools
+from juno_custom.ui import main as main_ui
+
+
+class GuiMainWindow(main_ui.Ui_MainWindow, QtWidgets.QMainWindow):
+ def __init__(self, viewer: napari.Viewer = None):
+ super(GuiMainWindow, self).__init__()
+ self.setupUi(self)
+ self.viewer = viewer
+ self.params = dict()
+
+ self.setup_viewer()
+ self.generate_element_list()
+ self.generate_options()
+ self.setup_connections()
+
+ def setup_viewer(self):
+ self.viewer.window._qt_viewer.dockLayerList.setVisible(False)
+ self.viewer.window._qt_viewer.dockLayerControls.setVisible(False)
+ self.viewer.window._qt_viewer.dockConsole.setVisible(False)
+
+ def setup_connections(self):
+ self.comboBox_Elements.currentTextChanged.connect(self.generate_options)
+ self.pushButton_GenerateProfile.clicked.connect(self.run_generate_profile)
+ self.pushButton_SaveProfile.clicked.connect(self.save_profile)
+ self.pushButton_SaveParameters.clicked.connect(self.save_parameters)
+
+ def generate_element_list(self):
+ # import custom elements from elements folder
+ element_list = element_tools.get_custom_elements()
+
+ self.comboBox_Elements.clear()
+
+ self.elements = dict()
+ for element in element_list:
+ self.comboBox_Elements.addItem(element.__name__)
+ self.elements[element.__name__] = {
+ "class": element,
+ "keys": element.__keys__(),
+ }
+
+ def generate_options(self):
+ element_name = self.comboBox_Elements.currentText()
+ print(f"Generating options for {element_name}...")
+
+ # clear options frame
+ for widget in self.frame_Options.children():
+ if isinstance(widget, QtWidgets.QWidget):
+ self.frame_Options.layout().removeWidget(widget)
+ widget.deleteLater()
+
+ # re/set layout
+ if self.frame_Options.layout() is None:
+ self.frame_Options.setLayout(QtWidgets.QVBoxLayout())
+
+ self.params = dict()
+ self.lineedits = dict()
+
+ # load in each key
+ for key, value in self.elements[element_name]["keys"].items():
+ self.params[key] = None
+
+ key_label = QtWidgets.QLabel(key)
+ key_label.setToolTip(value[4])
+
+ key_line_edit = QtWidgets.QLineEdit()
+ key_line_edit.setText(str(value[1]))
+ if value[3]:
+ key_line_edit.setEnabled(False)
+ self.lineedits[key] = key_line_edit
+
+ self.frame_Options.layout().addWidget(key_label)
+ self.frame_Options.layout().addWidget(key_line_edit)
+
+ def run_generate_profile(self):
+ self.pushButton_GenerateProfile.setEnabled(False)
+ element_name = self.comboBox_Elements.currentText()
+ params = self.get_parameters(element_name=element_name)
+ self.element = self.load_element(element_name)
+
+ worker = self.generate_profile(params=params)
+ worker.signals.finished.connect(self.plot_profile)
+ worker.signals.finished.connect(
+ lambda: self.pushButton_GenerateProfile.setEnabled(True)
+ )
+ worker.start()
+
+ def get_parameters(self, element_name: str):
+ params = dict()
+ for key in self.params.keys():
+ type_ = self.elements[element_name]["keys"][key][0]
+ params[key] = type_(self.lineedits[key].text())
+ return params
+
+ @thread_worker
+ def generate_profile(self, params):
+ self.element.generate_profile(params)
+
+ def plot_profile(self):
+ self.viewer.layers.clear()
+ self.viewer.add_image(self.element.profile, colormap="gray", name="element")
+
+ def load_element(self, element_name: str):
+ element = self.elements[element_name]["class"]()
+ return element
+
+ def save_profile(self):
+ filename, _ = QtWidgets.QFileDialog.getSaveFileName(
+ self, "Save Profile", "", "Numpy Arrays (*.npy)"
+ )
+ if filename:
+ np.save(filename, self.element.profile)
+
+ def save_parameters(self):
+ filename, _ = QtWidgets.QFileDialog.getSaveFileName(
+ self, "Save Parameters", "", "YAML (*.yml *.yaml)"
+ )
+ if filename:
+ parameters = self.get_parameters(
+ element_name=self.comboBox_Elements.currentText()
+ )
+ with open(filename, "w") as f:
+ yaml.dump(parameters, f, sort_keys=False)
+
+
+if __name__ == "__main__":
+ viewer = napari.Viewer(ndisplay=2)
+ user_interface = GuiMainWindow(viewer=viewer)
+ viewer.window.add_dock_widget(user_interface, area="right")
+ napari.run()
diff --git a/juno/juno_custom/utils.py b/juno/juno_custom/utils.py
new file mode 100644
index 0000000..2c0d937
--- /dev/null
+++ b/juno/juno_custom/utils.py
@@ -0,0 +1,23 @@
+import os
+
+import numpy as np
+import yaml
+
+
+def save_configuration(config: dict, profile: np.ndarray = None):
+ save_base = os.path.join(config["folder"], config["name"])
+
+ os.makedirs(config["folder"], exist_ok=True)
+
+ with open(save_base + ".yaml", "w") as f:
+ yaml.safe_dump(config, f, sort_keys=False)
+
+ if profile is not None:
+ np.save(save_base + ".npy", profile)
+
+
+def load_configuration(config_filename: str):
+ with open(config_filename, "r") as f:
+ config = yaml.safe_load(f)
+
+ return config
diff --git a/juno/lightsheet/light_sheet.py b/juno/lightsheet/light_sheet.py
index 8aba843..15b30c6 100644
--- a/juno/lightsheet/light_sheet.py
+++ b/juno/lightsheet/light_sheet.py
@@ -72,10 +72,14 @@ def calculate_longest_sheet(above_threshold):
def calculate_sheet_size_pixels(image, threshold_value):
+ # FIND PEAK VALUE along center
+ centre_max = np.max(image[:, image.shape[1] // 2])
+ index_max = np.where(image[:, image.shape[1] // 2] == centre_max)[0][0]
cz = image.shape[0] // 2
+ cz = index_max
cx = image.shape[1] // 2
- min_z, max_z = cz, cz
+ min_z, max_z = 0, image.shape[0]
# find min, max values less than threshold
for z_idx in range(cz, image.shape[0], 1):
val = image[z_idx, cx]
diff --git a/juno/plotting.py b/juno/plotting.py
index 311f4db..096a746 100644
--- a/juno/plotting.py
+++ b/juno/plotting.py
@@ -653,8 +653,9 @@ def create_3d_lens(lens: Lens) -> da.Array:
# scale profile by pixelsize
lens_profile = lens.profile / lens.pixel_size # profile height in pixels
-
+
l_max = int(np.max(lens_profile))
+ l_max = max(l_max, 1) # make sure l_max is at least 1
arr3d = np.ones(shape=(l_max, lens_profile.shape[0], lens_profile.shape[1]))
for y in range(lens.profile.shape[0]):
diff --git a/juno/run_simulation.py b/juno/run_simulation.py
index e06b435..4338063 100644
--- a/juno/run_simulation.py
+++ b/juno/run_simulation.py
@@ -6,15 +6,17 @@
def main(config_filename):
- if len(sys.argv) >= 2:
- config_filename = sys.argv[1]
- else:
- config_filename = os.path.join(os.path.dirname(juno.__file__), "config.yaml")
+ if config_filename is None:
+ if len(sys.argv) >= 2:
+ config_filename = sys.argv[1]
+ else:
+ config_filename = os.path.join(os.path.dirname(juno.__file__), "config.yaml")
sim_runner = SimulationRunner.SimulationRunner(config_filename)
sim_runner.setup_simulation()
sim_runner.run_simulations()
if __name__ == "__main__":
-
- main()
+ if len(sys.argv) >= 2:
+ config_filename = sys.argv[1]
+ main(config_filename)
diff --git a/juno/ui/BeamCreation.py b/juno/ui/BeamCreation.py
index cf5d93e..daaf973 100644
--- a/juno/ui/BeamCreation.py
+++ b/juno/ui/BeamCreation.py
@@ -73,7 +73,7 @@ def setup_connections(self):
self.lineEdit_gaussian_waist_x.textChanged.connect(self.update_visualisation)
self.lineEdit_gaussian_waist_y.textChanged.connect(self.update_visualisation)
self.lineEdit_gaussian_axial_z0.textChanged.connect(self.update_visualisation)
- self.lineEdit_gaussian_axial_z_total.textChanged.connect(self.update_visualisation)
+ # self.lineEdit_gaussian_axial_z_total.textChanged.connect(self.update_visualisation)
# simulation
self.lineEdit_pixelsize.textChanged.connect(self.update_visualisation)
@@ -131,7 +131,7 @@ def update_ui_from_config(self, config: dict):
self.lineEdit_gaussian_waist_x.setText(str(config["gaussian_wx"]))
self.lineEdit_gaussian_waist_y.setText(str(config["gaussian_wy"]))
self.lineEdit_gaussian_axial_z0.setText(str(config["gaussian_z0"]))
- self.lineEdit_gaussian_axial_z_total.setText(str(config["gaussian_z"]))
+ # self.lineEdit_gaussian_axial_z_total.setText(str(config["gaussian_z"]))
# simulation
if config["step_size"] is None:
@@ -191,17 +191,17 @@ def load_configuration(self):
if filename == "":
return
- # load beam config and validate
- beam_config = utils.load_yaml_config(filename)
- beam_config = validation._validate_default_beam_config(beam_config)
-
- # update ui
try:
+ # load beam config and validate
+ beam_config = utils.load_yaml_config(filename)
+ beam_config = validation._validate_default_beam_config(beam_config)
+
+ # update ui
self.update_ui_from_config(beam_config)
+ self.update_visualisation()
except:
napari.utils.notifications.show_error(traceback.format_exc())
- self.update_visualisation()
def save_configuration(self):
@@ -266,7 +266,7 @@ def update_config(self):
beam_config["gaussian_wx"] = float(self.lineEdit_gaussian_waist_x.text())
beam_config["gaussian_wy"] = float(self.lineEdit_gaussian_waist_y.text())
beam_config["gaussian_z0"] = float(self.lineEdit_gaussian_axial_z0.text())
- beam_config["gaussian_z"] = float(self.lineEdit_gaussian_axial_z_total.text())
+ # beam_config["gaussian_z"] = float(self.lineEdit_gaussian_axial_z_total.text())
# sim parameters
parameters_config["A"] = float(self.lineEdit_sim_amplitude.text())
@@ -370,9 +370,9 @@ def validate_beam_for_display(config: dict, parameters: SimulationParameters) ->
for k in ["width", "height"]:
if config["beam"][k] / parameters.pixel_size > BEAM_SHAPE_DISPLAY_LIMIT_PX:
valid_beam = False
-
- if config["beam"]["n_steps"] > BEAM_N_STEPS_DISPLAY_LIMIT:
- valid_beam = False
+ if "n_steps" in config["beam"]:
+ if config["beam"]["n_steps"] > BEAM_N_STEPS_DISPLAY_LIMIT:
+ valid_beam = False
if "step_size" in config["beam"]:
if config["beam"]["step_size"] < BEAM_STEP_SIZE_DISPLAY_LIMIT:
valid_beam = False
diff --git a/juno/ui/ElementCreation.py b/juno/ui/ElementCreation.py
index 65d385c..f266aeb 100644
--- a/juno/ui/ElementCreation.py
+++ b/juno/ui/ElementCreation.py
@@ -67,7 +67,7 @@ def setup_connections(self):
self.lineEdit_height.textChanged.connect(self.update_visualisation)
self.lineEdit_medium.textChanged.connect(self.update_visualisation)
self.lineEdit_exponent.textChanged.connect(self.update_visualisation)
- self.lineEdit_escape_path.textChanged.connect(self.update_visualisation)
+ self.doubleSpinBox_escape_path.valueChanged.connect(self.update_visualisation)
self.comboBox_type.currentTextChanged.connect(self.update_visualisation)
self.checkBox_invert_profile.stateChanged.connect(self.update_visualisation)
self.lineEdit_name.textChanged.connect(self.update_visualisation)
@@ -122,7 +122,7 @@ def update_ui_from_config(self, config: dict):
self.lineEdit_height.setText(str(config["height"]))
self.lineEdit_medium.setText(str(config["medium"]))
self.lineEdit_exponent.setText(str(config["exponent"]))
- self.lineEdit_escape_path.setText(str(config["escape_path"]))
+ self.doubleSpinBox_escape_path.setValue(float(config["escape_path"]))
self.comboBox_type.setCurrentText(str(config["lens_type"]).capitalize())
self.checkBox_invert_profile.setChecked(bool(config["inverted"]))
self.lineEdit_name.setText(str(config["name"]))
@@ -137,7 +137,7 @@ def update_ui_from_config(self, config: dict):
self.checkBox_grating_x_axis.setChecked(bool(config["grating"]["x"]))
self.checkBox_grating_y_axis.setChecked(bool(config["grating"]["y"]))
self.checkBox_grating_centred.setChecked(bool(config["grating"]["centred"]))
- self.lineEdit_grating_blur.setText(float(config["grating"]["blur"]))
+ self.lineEdit_grating_blur.setText(str(config["grating"]["blur"]))
self.comboBox_grating_mode.setCurrentText(config["grating"]["mode"])
self.lineEdit_grating_inner_radius.setText(str(config["grating"]["inner_radius"]))
@@ -337,7 +337,7 @@ def update_config(self):
lens_config["diameter"] = float(self.lineEdit_diameter.text())
lens_config["exponent"] = float(self.lineEdit_exponent.text())
lens_config["inverted"] = bool(self.checkBox_invert_profile.isChecked())
- lens_config["escape_path"] = float(self.lineEdit_escape_path.text())
+ lens_config["escape_path"] = float(self.doubleSpinBox_escape_path.value())
lens_config["length"] = float(self.lineEdit_length.text())
lens_config["lens_type"] = self.comboBox_type.currentText()
lens_config["name"] = self.lineEdit_name.text()
diff --git a/juno/ui/SimulationSetup.py b/juno/ui/SimulationSetup.py
index 062154b..999d148 100644
--- a/juno/ui/SimulationSetup.py
+++ b/juno/ui/SimulationSetup.py
@@ -26,19 +26,19 @@ def __init__(self, viewer: napari.Viewer = None, parent_gui=None):
self.statusBar = QtWidgets.QStatusBar()
self.setStatusBar(self.statusBar)
self.setWindowTitle("Simulation Setup")
-
self.viewer: napari.Viewer = viewer
self.simulation_config = {}
self.SAVE_FROM_PARAMETER_SWEEP = False
self.input_widgets = []
+ self._validated_simulation_config = False
self.setup_connections()
self.update_all_displays()
- self.showNormal()
+ self._update_ui_components()
def setup_connections(self):
@@ -52,13 +52,30 @@ def setup_connections(self):
)
self.pushButton_sim_beam.clicked.connect(self.load_beam_config)
self.pushButton_setup_parameter_sweep.clicked.connect(self.setup_parameter_sweep)
+ self.pushButton_visualise_simulation.clicked.connect(self.visualise_simulation)
# actions
self.actionLoad_Configuration.triggered.connect(self.load_simulation_config)
self.actionSave_Configuration.triggered.connect(self.save_simulation_config)
- # off by default
- self.actionSave_Configuration.setEnabled(False)
+ def _update_ui_components(self):
+
+ # clear viewer
+ self.viewer.layers.clear()
+
+ # enable parameter sweep
+ self.pushButton_setup_parameter_sweep.setVisible(self._validated_simulation_config)
+ self.pushButton_setup_parameter_sweep.setEnabled(self._validated_simulation_config)
+
+ # enable saving
+ self.actionSave_Configuration.setEnabled(self._validated_simulation_config)
+
+ # enable visualisation
+ self.label_visualisation_scale.setVisible(self._validated_simulation_config)
+ self.spinBox_visualisation_scale.setVisible(self._validated_simulation_config)
+ self.pushButton_visualise_simulation.setVisible(self._validated_simulation_config)
+ self.pushButton_visualise_simulation.setEnabled(self._validated_simulation_config)
+
def update_all_displays(self):
@@ -120,7 +137,7 @@ def save_simulation_config(self):
with open(sim_config_filename, "w") as f:
yaml.safe_dump(self.simulation_config, f)
- self.statusBar.showMessage(f"Simulation config saved to {sim_config_filename}")
+ napari.utils.notifications.show_info(f"Simulation config saved to {sim_config_filename}")
def load_simulation_config(self):
@@ -162,6 +179,10 @@ def load_simulation_config(self):
load_stage_config_widgets(config, self.input_widgets)
self.SIMULATION_CONFIG_LOADED = True
+ # update ui
+ self._validated_simulation_config = False
+ self._update_ui_components()
+
def update_status(self, msg= "Generating Simulation Configuration..."):
"""update status within button press..."""
napari.utils.notifications.show_info(msg)
@@ -177,11 +198,11 @@ def generate_simulation_config(self):
self.read_stage_input_values()
validation._validate_simulation_config(self.simulation_config)
- napari.utils.notifications.show_info(f"Valid Simulation Configuration. Plotting Setup...")
- self.draw_simulation_stage_display()
+ napari.utils.notifications.show_info(f"Valid Simulation Configuration.")
- self.pushButton_setup_parameter_sweep.setEnabled(True)
- self.actionSave_Configuration.setEnabled(True)
+ # update ui
+ self._validated_simulation_config = True
+ self._update_ui_components()
napari.utils.notifications.show_info(f"Generate Simulation Configuration Finished.")
@@ -192,7 +213,11 @@ def generate_simulation_config(self):
- def draw_simulation_stage_display(self):
+ def visualise_simulation(self):
+
+ self.pushButton_visualise_simulation.setEnabled(False)
+ self.pushButton_visualise_simulation.setText("Visualising...")
+ self.pushButton_visualise_simulation.setStyleSheet("background-color: orange")
# TODO: find a way to make the viewing of this much more performant
pixel_size = self.simulation_config["sim_parameters"]["pixel_size"]
@@ -221,6 +246,10 @@ def draw_simulation_stage_display(self):
# reset pixel_size
self.simulation_config["sim_parameters"]["pixel_size"] = pixel_size
+ self.pushButton_visualise_simulation.setEnabled(False)
+ self.pushButton_visualise_simulation.setText("Visualise Simulation")
+ self.pushButton_visualise_simulation.setStyleSheet("background-color: gray")
+
def read_stage_input_values(self):
stage_configs = []
@@ -332,8 +361,6 @@ def load_beam_config(self):
def update_stage_input_display(self):
- print("updating stage display")
-
sim_num_stages = int(self.spinBox_sim_num_stages.value())
input_layout = QVBoxLayout()
@@ -493,16 +520,11 @@ def load_stage_config_widgets(config, all_widgets):
widgets[14].setText(str(stage_config["focal_distance_multiple"]))
def main():
- """Launch the main application window. """
- application = QtWidgets.QApplication([])
import napari
viewer = napari.Viewer(ndisplay=3)
simulation_setup_ui = GUISimulationSetup(viewer=viewer)
viewer.window.add_dock_widget(simulation_setup_ui, area='right')
-
- application.aboutToQuit.connect(simulation_setup_ui.disconnect) # cleanup & teardown
- sys.exit(application.exec_())
-
+ napari.run()
if __name__ == "__main__":
main()
diff --git a/juno/ui/qtdesigner_files/BeamCreation.py b/juno/ui/qtdesigner_files/BeamCreation.py
index 3e4d70f..f56cb9e 100644
--- a/juno/ui/qtdesigner_files/BeamCreation.py
+++ b/juno/ui/qtdesigner_files/BeamCreation.py
@@ -14,7 +14,7 @@
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
- MainWindow.resize(396, 700)
+ MainWindow.resize(418, 700)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
@@ -160,9 +160,6 @@ def setupUi(self, MainWindow):
self.tab.setObjectName("tab")
self.gridLayout_7 = QtWidgets.QGridLayout(self.tab)
self.gridLayout_7.setObjectName("gridLayout_7")
- self.label_gaussian_z_total = QtWidgets.QLabel(self.tab)
- self.label_gaussian_z_total.setObjectName("label_gaussian_z_total")
- self.gridLayout_7.addWidget(self.label_gaussian_z_total, 5, 0, 1, 1)
self.label_gaussian_header = QtWidgets.QLabel(self.tab)
font = QtGui.QFont()
font.setBold(True)
@@ -187,15 +184,15 @@ def setupUi(self, MainWindow):
self.gridLayout_7.addWidget(self.lineEdit_gaussian_axial_z0, 4, 1, 1, 1)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_7.addItem(spacerItem1, 6, 0, 1, 2)
- self.lineEdit_gaussian_axial_z_total = QtWidgets.QLineEdit(self.tab)
- self.lineEdit_gaussian_axial_z_total.setObjectName("lineEdit_gaussian_axial_z_total")
- self.gridLayout_7.addWidget(self.lineEdit_gaussian_axial_z_total, 5, 1, 1, 1)
self.label_gaussian_z0 = QtWidgets.QLabel(self.tab)
self.label_gaussian_z0.setObjectName("label_gaussian_z0")
self.gridLayout_7.addWidget(self.label_gaussian_z0, 4, 0, 1, 1)
self.label_gaussian_waist_y = QtWidgets.QLabel(self.tab)
self.label_gaussian_waist_y.setObjectName("label_gaussian_waist_y")
self.gridLayout_7.addWidget(self.label_gaussian_waist_y, 3, 0, 1, 1)
+ self.label_gaussian_z_total = QtWidgets.QLabel(self.tab)
+ self.label_gaussian_z_total.setObjectName("label_gaussian_z_total")
+ self.gridLayout_7.addWidget(self.label_gaussian_z_total, 5, 0, 1, 2)
self.tabWidget.addTab(self.tab, "")
self.tab_grating = QtWidgets.QWidget()
self.tab_grating.setObjectName("tab_grating")
@@ -278,7 +275,7 @@ def setupUi(self, MainWindow):
self.gridLayout.addWidget(self.frame_main, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
- self.menubar.setGeometry(QtCore.QRect(0, 0, 396, 21))
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 418, 21))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@@ -295,8 +292,35 @@ def setupUi(self, MainWindow):
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
- self.tabWidget.setCurrentIndex(0)
+ self.tabWidget.setCurrentIndex(2)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
+ MainWindow.setTabOrder(self.tabWidget, self.lineEdit_name)
+ MainWindow.setTabOrder(self.lineEdit_name, self.lineEdit_beam_width)
+ MainWindow.setTabOrder(self.lineEdit_beam_width, self.lineEdit_beam_height)
+ MainWindow.setTabOrder(self.lineEdit_beam_height, self.lineEdit_shift_x)
+ MainWindow.setTabOrder(self.lineEdit_shift_x, self.lineEdit_shift_y)
+ MainWindow.setTabOrder(self.lineEdit_shift_y, self.comboBox_spread)
+ MainWindow.setTabOrder(self.comboBox_spread, self.comboBox_shape)
+ MainWindow.setTabOrder(self.comboBox_shape, self.comboBox_convergence)
+ MainWindow.setTabOrder(self.comboBox_convergence, self.lineEdit_convergence_value)
+ MainWindow.setTabOrder(self.lineEdit_convergence_value, self.comboBox_distance_mode)
+ MainWindow.setTabOrder(self.comboBox_distance_mode, self.lineEdit_distance_value)
+ MainWindow.setTabOrder(self.lineEdit_distance_value, self.lineEdit_tilt_x)
+ MainWindow.setTabOrder(self.lineEdit_tilt_x, self.lineEdit_tilt_y)
+ MainWindow.setTabOrder(self.lineEdit_tilt_y, self.checkBox_live_update)
+ MainWindow.setTabOrder(self.checkBox_live_update, self.pushButton_generate_beam)
+ MainWindow.setTabOrder(self.pushButton_generate_beam, self.checkBox_gaussian_enabled)
+ MainWindow.setTabOrder(self.checkBox_gaussian_enabled, self.lineEdit_gaussian_waist_x)
+ MainWindow.setTabOrder(self.lineEdit_gaussian_waist_x, self.lineEdit_gaussian_waist_y)
+ MainWindow.setTabOrder(self.lineEdit_gaussian_waist_y, self.lineEdit_gaussian_axial_z0)
+ MainWindow.setTabOrder(self.lineEdit_gaussian_axial_z0, self.lineEdit_pixelsize)
+ MainWindow.setTabOrder(self.lineEdit_pixelsize, self.lineEdit_sim_width)
+ MainWindow.setTabOrder(self.lineEdit_sim_width, self.lineEdit_sim_height)
+ MainWindow.setTabOrder(self.lineEdit_sim_height, self.lineEdit_sim_wavelength)
+ MainWindow.setTabOrder(self.lineEdit_sim_wavelength, self.lineEdit_sim_amplitude)
+ MainWindow.setTabOrder(self.lineEdit_sim_amplitude, self.comboBox_propagation_type)
+ MainWindow.setTabOrder(self.comboBox_propagation_type, self.lineEdit_propagation_step)
+ MainWindow.setTabOrder(self.lineEdit_propagation_step, self.lineEdit_medium)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
@@ -328,12 +352,12 @@ def retranslateUi(self, MainWindow):
self.lineEdit_tilt_y.setText(_translate("MainWindow", "0.0"))
self.label_tilt_header.setText(_translate("MainWindow", "Tilt"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_general), _translate("MainWindow", "General"))
- self.label_gaussian_z_total.setText(_translate("MainWindow", "Total Distance (z)"))
self.label_gaussian_header.setText(_translate("MainWindow", "Gaussian"))
self.checkBox_gaussian_enabled.setText(_translate("MainWindow", "Enable Gaussian Beam"))
self.label_gaussian_waist_x.setText(_translate("MainWindow", "Waist Radius (X)"))
self.label_gaussian_z0.setText(_translate("MainWindow", "Axial Distance (z0)"))
self.label_gaussian_waist_y.setText(_translate("MainWindow", "Waist Radius (Y)"))
+ self.label_gaussian_z_total.setText(_translate("MainWindow", "Total Distance (z) is controlled by propagation distance in the General tab."))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Gaussian"))
self.label.setText(_translate("MainWindow", "Wavelength (m)"))
self.label_pixelsize.setText(_translate("MainWindow", "Pixel Size"))
diff --git a/juno/ui/qtdesigner_files/BeamCreation.ui b/juno/ui/qtdesigner_files/BeamCreation.ui
index ed0bb41..f2cc59c 100644
--- a/juno/ui/qtdesigner_files/BeamCreation.ui
+++ b/juno/ui/qtdesigner_files/BeamCreation.ui
@@ -6,7 +6,7 @@
0
0
- 396
+ 418
700
@@ -51,7 +51,7 @@
QTabWidget::Rounded
- 0
+ 2
@@ -299,13 +299,6 @@
Gaussian
- -
-
-
- Total Distance (z)
-
-
-
-
@@ -355,9 +348,6 @@
- -
-
-
-
@@ -372,6 +362,13 @@
+ -
+
+
+ Total Distance (z) is controlled by propagation distance in the General tab.
+
+
+
@@ -553,7 +550,7 @@
0
0
- 396
+ 418
21
@@ -578,6 +575,36 @@
+
+ tabWidget
+ lineEdit_name
+ lineEdit_beam_width
+ lineEdit_beam_height
+ lineEdit_shift_x
+ lineEdit_shift_y
+ comboBox_spread
+ comboBox_shape
+ comboBox_convergence
+ lineEdit_convergence_value
+ comboBox_distance_mode
+ lineEdit_distance_value
+ lineEdit_tilt_x
+ lineEdit_tilt_y
+ checkBox_live_update
+ pushButton_generate_beam
+ checkBox_gaussian_enabled
+ lineEdit_gaussian_waist_x
+ lineEdit_gaussian_waist_y
+ lineEdit_gaussian_axial_z0
+ lineEdit_pixelsize
+ lineEdit_sim_width
+ lineEdit_sim_height
+ lineEdit_sim_wavelength
+ lineEdit_sim_amplitude
+ comboBox_propagation_type
+ lineEdit_propagation_step
+ lineEdit_medium
+
diff --git a/juno/ui/qtdesigner_files/ElementCreation.py b/juno/ui/qtdesigner_files/ElementCreation.py
index 75d59fd..7f23840 100644
--- a/juno/ui/qtdesigner_files/ElementCreation.py
+++ b/juno/ui/qtdesigner_files/ElementCreation.py
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'ElementCreation.ui'
#
-# Created by: PyQt5 UI code generator 5.15.7
+# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -74,9 +74,6 @@ def setupUi(self, MainWindow):
self.label_diameter = QtWidgets.QLabel(self.groupBox)
self.label_diameter.setObjectName("label_diameter")
self.gridLayout_3.addWidget(self.label_diameter, 2, 0, 1, 1)
- self.lineEdit_escape_path = QtWidgets.QLineEdit(self.groupBox)
- self.lineEdit_escape_path.setObjectName("lineEdit_escape_path")
- self.gridLayout_3.addWidget(self.lineEdit_escape_path, 8, 1, 1, 1)
self.lineEdit_exponent = QtWidgets.QLineEdit(self.groupBox)
self.lineEdit_exponent.setObjectName("lineEdit_exponent")
self.gridLayout_3.addWidget(self.lineEdit_exponent, 5, 1, 1, 1)
@@ -98,6 +95,11 @@ def setupUi(self, MainWindow):
self.checkBox_invert_profile = QtWidgets.QCheckBox(self.groupBox)
self.checkBox_invert_profile.setObjectName("checkBox_invert_profile")
self.gridLayout_3.addWidget(self.checkBox_invert_profile, 9, 0, 1, 2)
+ self.doubleSpinBox_escape_path = QtWidgets.QDoubleSpinBox(self.groupBox)
+ self.doubleSpinBox_escape_path.setMaximum(2.0)
+ self.doubleSpinBox_escape_path.setSingleStep(0.01)
+ self.doubleSpinBox_escape_path.setObjectName("doubleSpinBox_escape_path")
+ self.gridLayout_3.addWidget(self.doubleSpinBox_escape_path, 8, 1, 1, 1)
self.gridLayout_4.addWidget(self.groupBox, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab_general, "")
self.tab_grating = QtWidgets.QWidget()
@@ -258,9 +260,11 @@ def setupUi(self, MainWindow):
self.checkBox_live_update.setObjectName("checkBox_live_update")
self.gridLayout_2.addWidget(self.checkBox_live_update, 2, 0, 1, 1)
self.gridLayout.addWidget(self.frame_main, 0, 0, 1, 1)
+ spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout.addItem(spacerItem2, 1, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
- self.menubar.setGeometry(QtCore.QRect(0, 0, 365, 20))
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 365, 21))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@@ -283,8 +287,38 @@ def setupUi(self, MainWindow):
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
- self.tabWidget.setCurrentIndex(1)
+ self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
+ MainWindow.setTabOrder(self.tabWidget, self.lineEdit_name)
+ MainWindow.setTabOrder(self.lineEdit_name, self.lineEdit_pixelsize)
+ MainWindow.setTabOrder(self.lineEdit_pixelsize, self.lineEdit_diameter)
+ MainWindow.setTabOrder(self.lineEdit_diameter, self.lineEdit_length)
+ MainWindow.setTabOrder(self.lineEdit_length, self.lineEdit_height)
+ MainWindow.setTabOrder(self.lineEdit_height, self.lineEdit_exponent)
+ MainWindow.setTabOrder(self.lineEdit_exponent, self.lineEdit_medium)
+ MainWindow.setTabOrder(self.lineEdit_medium, self.comboBox_type)
+ MainWindow.setTabOrder(self.comboBox_type, self.checkBox_invert_profile)
+ MainWindow.setTabOrder(self.checkBox_invert_profile, self.checkBox_live_update)
+ MainWindow.setTabOrder(self.checkBox_live_update, self.pushButton_generate_profile)
+ MainWindow.setTabOrder(self.pushButton_generate_profile, self.comboBox_truncation_mode)
+ MainWindow.setTabOrder(self.comboBox_truncation_mode, self.checkBox_use_truncation)
+ MainWindow.setTabOrder(self.checkBox_use_truncation, self.checkBox_grating_y_axis)
+ MainWindow.setTabOrder(self.checkBox_grating_y_axis, self.lineEdit_grating_depth)
+ MainWindow.setTabOrder(self.lineEdit_grating_depth, self.checkBox_grating_centred)
+ MainWindow.setTabOrder(self.checkBox_grating_centred, self.checkBox_aperture_invert)
+ MainWindow.setTabOrder(self.checkBox_aperture_invert, self.comboBox_grating_mode)
+ MainWindow.setTabOrder(self.comboBox_grating_mode, self.lineEdit_grating_inner_radius)
+ MainWindow.setTabOrder(self.lineEdit_grating_inner_radius, self.lineEdit_aperture_outer)
+ MainWindow.setTabOrder(self.lineEdit_aperture_outer, self.lineEdit_grating_distance)
+ MainWindow.setTabOrder(self.lineEdit_grating_distance, self.checkBox_use_aperture)
+ MainWindow.setTabOrder(self.checkBox_use_aperture, self.comboBox_aperture_mode)
+ MainWindow.setTabOrder(self.comboBox_aperture_mode, self.lineEdit_truncation_value)
+ MainWindow.setTabOrder(self.lineEdit_truncation_value, self.checkBox_grating_x_axis)
+ MainWindow.setTabOrder(self.checkBox_grating_x_axis, self.checkBox_truncation_aperture)
+ MainWindow.setTabOrder(self.checkBox_truncation_aperture, self.lineEdit_aperture_inner)
+ MainWindow.setTabOrder(self.lineEdit_aperture_inner, self.lineEdit_grating_blur)
+ MainWindow.setTabOrder(self.lineEdit_grating_blur, self.lineEdit_grating_width)
+ MainWindow.setTabOrder(self.lineEdit_grating_width, self.checkBox_use_grating)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
@@ -299,7 +333,6 @@ def retranslateUi(self, MainWindow):
self.lineEdit_diameter.setText(_translate("MainWindow", "100e-6"))
self.lineEdit_medium.setText(_translate("MainWindow", "2.348"))
self.label_diameter.setText(_translate("MainWindow", "Diameter (m)"))
- self.lineEdit_escape_path.setText(_translate("MainWindow", "0.0"))
self.lineEdit_exponent.setText(_translate("MainWindow", "2.0"))
self.label_exponent.setText(_translate("MainWindow", "Exponent"))
self.lineEdit_height.setText(_translate("MainWindow", "50e-6"))
diff --git a/juno/ui/qtdesigner_files/ElementCreation.ui b/juno/ui/qtdesigner_files/ElementCreation.ui
index dbddf0e..ed04e3f 100644
--- a/juno/ui/qtdesigner_files/ElementCreation.ui
+++ b/juno/ui/qtdesigner_files/ElementCreation.ui
@@ -30,7 +30,7 @@
QTabWidget::Rounded
- 1
+ 0
@@ -135,13 +135,6 @@
- -
-
-
- 0.0
-
-
-
-
@@ -191,6 +184,16 @@
+ -
+
+
+ 2.000000000000000
+
+
+ 0.010000000000000
+
+
+
@@ -515,6 +518,19 @@
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+ pushButton_create_element
+ pushButton_create_beam
+ pushButton_setup_sim
+ pushButton_run_simulation
+ pushButton_view_results
+
diff --git a/juno/ui/qtdesigner_files/SimulationSetup.py b/juno/ui/qtdesigner_files/SimulationSetup.py
index 8ffef05..45cadae 100644
--- a/juno/ui/qtdesigner_files/SimulationSetup.py
+++ b/juno/ui/qtdesigner_files/SimulationSetup.py
@@ -19,6 +19,117 @@ def setupUi(self, MainWindow):
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
+ self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
+ self.tabWidget.setObjectName("tabWidget")
+ self.tab_simulation = QtWidgets.QWidget()
+ self.tab_simulation.setObjectName("tab_simulation")
+ self.gridLayout_6 = QtWidgets.QGridLayout(self.tab_simulation)
+ self.gridLayout_6.setObjectName("gridLayout_6")
+ self.lineEdit_log_dir = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_log_dir.setObjectName("lineEdit_log_dir")
+ self.gridLayout_6.addWidget(self.lineEdit_log_dir, 8, 1, 1, 1)
+ self.label_sim_amplitude = QtWidgets.QLabel(self.tab_simulation)
+ self.label_sim_amplitude.setObjectName("label_sim_amplitude")
+ self.gridLayout_6.addWidget(self.label_sim_amplitude, 5, 0, 1, 1)
+ self.label_options_title = QtWidgets.QLabel(self.tab_simulation)
+ font = QtGui.QFont()
+ font.setPointSize(10)
+ font.setBold(True)
+ font.setWeight(75)
+ self.label_options_title.setFont(font)
+ self.label_options_title.setObjectName("label_options_title")
+ self.gridLayout_6.addWidget(self.label_options_title, 7, 0, 1, 1)
+ self.label_sim_width = QtWidgets.QLabel(self.tab_simulation)
+ self.label_sim_width.setObjectName("label_sim_width")
+ self.gridLayout_6.addWidget(self.label_sim_width, 2, 0, 1, 1)
+ self.label_sim_param_title = QtWidgets.QLabel(self.tab_simulation)
+ font = QtGui.QFont()
+ font.setPointSize(10)
+ font.setBold(True)
+ font.setWeight(75)
+ self.label_sim_param_title.setFont(font)
+ self.label_sim_param_title.setObjectName("label_sim_param_title")
+ self.gridLayout_6.addWidget(self.label_sim_param_title, 0, 0, 1, 1)
+ self.lineEdit_sim_name = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_sim_name.setObjectName("lineEdit_sim_name")
+ self.gridLayout_6.addWidget(self.lineEdit_sim_name, 9, 1, 1, 1)
+ self.label_sim_beam = QtWidgets.QLabel(self.tab_simulation)
+ self.label_sim_beam.setObjectName("label_sim_beam")
+ self.gridLayout_6.addWidget(self.label_sim_beam, 6, 0, 1, 1)
+ self.lineEdit_pixel_size = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_pixel_size.setObjectName("lineEdit_pixel_size")
+ self.gridLayout_6.addWidget(self.lineEdit_pixel_size, 1, 1, 1, 1)
+ self.label_sim_wavelength = QtWidgets.QLabel(self.tab_simulation)
+ self.label_sim_wavelength.setObjectName("label_sim_wavelength")
+ self.gridLayout_6.addWidget(self.label_sim_wavelength, 4, 0, 1, 1)
+ self.label_sim_name = QtWidgets.QLabel(self.tab_simulation)
+ self.label_sim_name.setObjectName("label_sim_name")
+ self.gridLayout_6.addWidget(self.label_sim_name, 9, 0, 1, 1)
+ self.pushButton_sim_beam = QtWidgets.QPushButton(self.tab_simulation)
+ self.pushButton_sim_beam.setObjectName("pushButton_sim_beam")
+ self.gridLayout_6.addWidget(self.pushButton_sim_beam, 6, 1, 1, 1)
+ self.label_2 = QtWidgets.QLabel(self.tab_simulation)
+ self.label_2.setObjectName("label_2")
+ self.gridLayout_6.addWidget(self.label_2, 8, 0, 1, 1)
+ self.lineEdit_sim_width = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_sim_width.setObjectName("lineEdit_sim_width")
+ self.gridLayout_6.addWidget(self.lineEdit_sim_width, 2, 1, 1, 1)
+ self.checkBox_save_plot = QtWidgets.QCheckBox(self.tab_simulation)
+ self.checkBox_save_plot.setChecked(True)
+ self.checkBox_save_plot.setObjectName("checkBox_save_plot")
+ self.gridLayout_6.addWidget(self.checkBox_save_plot, 10, 1, 1, 1)
+ self.lineEdit_sim_height = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_sim_height.setObjectName("lineEdit_sim_height")
+ self.gridLayout_6.addWidget(self.lineEdit_sim_height, 3, 1, 1, 1)
+ self.label_pixel_size = QtWidgets.QLabel(self.tab_simulation)
+ self.label_pixel_size.setObjectName("label_pixel_size")
+ self.gridLayout_6.addWidget(self.label_pixel_size, 1, 0, 1, 1)
+ self.lineEdit_sim_wavelength = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_sim_wavelength.setObjectName("lineEdit_sim_wavelength")
+ self.gridLayout_6.addWidget(self.lineEdit_sim_wavelength, 4, 1, 1, 1)
+ self.label_sim_height = QtWidgets.QLabel(self.tab_simulation)
+ self.label_sim_height.setObjectName("label_sim_height")
+ self.gridLayout_6.addWidget(self.label_sim_height, 3, 0, 1, 1)
+ self.lineEdit_sim_amplitude = QtWidgets.QLineEdit(self.tab_simulation)
+ self.lineEdit_sim_amplitude.setObjectName("lineEdit_sim_amplitude")
+ self.gridLayout_6.addWidget(self.lineEdit_sim_amplitude, 5, 1, 1, 1)
+ spacerItem = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
+ self.gridLayout_6.addItem(spacerItem, 11, 0, 1, 2)
+ self.tabWidget.addTab(self.tab_simulation, "")
+ self.tab_stages = QtWidgets.QWidget()
+ self.tab_stages.setObjectName("tab_stages")
+ self.gridLayout_7 = QtWidgets.QGridLayout(self.tab_stages)
+ self.gridLayout_7.setObjectName("gridLayout_7")
+ self.label_sim_num_stages = QtWidgets.QLabel(self.tab_stages)
+ self.label_sim_num_stages.setObjectName("label_sim_num_stages")
+ self.gridLayout_7.addWidget(self.label_sim_num_stages, 1, 0, 1, 1)
+ self.spinBox_sim_num_stages = QtWidgets.QSpinBox(self.tab_stages)
+ self.spinBox_sim_num_stages.setMinimum(1)
+ self.spinBox_sim_num_stages.setMaximum(10)
+ self.spinBox_sim_num_stages.setSingleStep(1)
+ self.spinBox_sim_num_stages.setObjectName("spinBox_sim_num_stages")
+ self.gridLayout_7.addWidget(self.spinBox_sim_num_stages, 1, 1, 1, 1)
+ self.label_stage_parameters_title = QtWidgets.QLabel(self.tab_stages)
+ font = QtGui.QFont()
+ font.setPointSize(10)
+ font.setBold(True)
+ font.setWeight(75)
+ self.label_stage_parameters_title.setFont(font)
+ self.label_stage_parameters_title.setObjectName("label_stage_parameters_title")
+ self.gridLayout_7.addWidget(self.label_stage_parameters_title, 0, 0, 1, 1)
+ self.scrollArea_stages = QtWidgets.QScrollArea(self.tab_stages)
+ self.scrollArea_stages.setMinimumSize(QtCore.QSize(0, 0))
+ self.scrollArea_stages.setWidgetResizable(True)
+ self.scrollArea_stages.setObjectName("scrollArea_stages")
+ self.scrollAreaWidgetContents = QtWidgets.QWidget()
+ self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 364, 141))
+ self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
+ self.scrollArea_stages.setWidget(self.scrollAreaWidgetContents)
+ self.gridLayout_7.addWidget(self.scrollArea_stages, 2, 0, 1, 2)
+ spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout_7.addItem(spacerItem1, 3, 0, 1, 2)
+ self.tabWidget.addTab(self.tab_stages, "")
+ self.gridLayout.addWidget(self.tabWidget, 1, 0, 1, 1)
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
@@ -34,145 +145,37 @@ def setupUi(self, MainWindow):
self.frame_2.setObjectName("frame_2")
self.gridLayout_3 = QtWidgets.QGridLayout(self.frame_2)
self.gridLayout_3.setObjectName("gridLayout_3")
- self.label = QtWidgets.QLabel(self.frame_2)
- self.label.setMaximumSize(QtCore.QSize(16777215, 200))
- font = QtGui.QFont()
- font.setPointSize(16)
- font.setBold(True)
- font.setWeight(75)
- self.label.setFont(font)
- self.label.setObjectName("label")
- self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1)
- self.label_visualisation_scale = QtWidgets.QLabel(self.frame_2)
- self.label_visualisation_scale.setObjectName("label_visualisation_scale")
- self.gridLayout_3.addWidget(self.label_visualisation_scale, 2, 0, 1, 1)
self.spinBox_visualisation_scale = QtWidgets.QSpinBox(self.frame_2)
self.spinBox_visualisation_scale.setMinimum(1)
self.spinBox_visualisation_scale.setMaximum(1000)
self.spinBox_visualisation_scale.setObjectName("spinBox_visualisation_scale")
- self.gridLayout_3.addWidget(self.spinBox_visualisation_scale, 2, 1, 1, 1)
- self.scrollArea = QtWidgets.QScrollArea(self.frame_2)
- self.scrollArea.setWidgetResizable(True)
- self.scrollArea.setObjectName("scrollArea")
- self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()
- self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 366, 707))
- self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2")
- self.gridLayout_5 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2)
- self.gridLayout_5.setObjectName("gridLayout_5")
- self.frame_4 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2)
- self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_4.setObjectName("frame_4")
- self.gridLayout_4 = QtWidgets.QGridLayout(self.frame_4)
- self.gridLayout_4.setObjectName("gridLayout_4")
- self.label_sim_wavelength = QtWidgets.QLabel(self.frame_4)
- self.label_sim_wavelength.setObjectName("label_sim_wavelength")
- self.gridLayout_4.addWidget(self.label_sim_wavelength, 7, 0, 1, 1)
- spacerItem = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
- self.gridLayout_4.addItem(spacerItem, 21, 0, 1, 2)
- self.label_sim_amplitude = QtWidgets.QLabel(self.frame_4)
- self.label_sim_amplitude.setObjectName("label_sim_amplitude")
- self.gridLayout_4.addWidget(self.label_sim_amplitude, 8, 0, 1, 1)
- self.label_stage_parameters_title = QtWidgets.QLabel(self.frame_4)
- font = QtGui.QFont()
- font.setPointSize(10)
- font.setBold(True)
- font.setWeight(75)
- self.label_stage_parameters_title.setFont(font)
- self.label_stage_parameters_title.setObjectName("label_stage_parameters_title")
- self.gridLayout_4.addWidget(self.label_stage_parameters_title, 14, 0, 1, 1)
- self.label_sim_width = QtWidgets.QLabel(self.frame_4)
- self.label_sim_width.setObjectName("label_sim_width")
- self.gridLayout_4.addWidget(self.label_sim_width, 5, 0, 1, 1)
- self.spinBox_sim_num_stages = QtWidgets.QSpinBox(self.frame_4)
- self.spinBox_sim_num_stages.setMinimum(1)
- self.spinBox_sim_num_stages.setMaximum(10)
- self.spinBox_sim_num_stages.setSingleStep(1)
- self.spinBox_sim_num_stages.setObjectName("spinBox_sim_num_stages")
- self.gridLayout_4.addWidget(self.spinBox_sim_num_stages, 15, 1, 1, 1)
- self.scrollArea_stages = QtWidgets.QScrollArea(self.frame_4)
- self.scrollArea_stages.setMinimumSize(QtCore.QSize(0, 0))
- self.scrollArea_stages.setWidgetResizable(True)
- self.scrollArea_stages.setObjectName("scrollArea_stages")
- self.scrollAreaWidgetContents = QtWidgets.QWidget()
- self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 326, 184))
- self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
- self.scrollArea_stages.setWidget(self.scrollAreaWidgetContents)
- self.gridLayout_4.addWidget(self.scrollArea_stages, 17, 0, 4, 2)
- self.label_sim_param_title = QtWidgets.QLabel(self.frame_4)
- font = QtGui.QFont()
- font.setPointSize(10)
- font.setBold(True)
- font.setWeight(75)
- self.label_sim_param_title.setFont(font)
- self.label_sim_param_title.setObjectName("label_sim_param_title")
- self.gridLayout_4.addWidget(self.label_sim_param_title, 0, 0, 1, 2)
- self.pushButton_sim_beam = QtWidgets.QPushButton(self.frame_4)
- self.pushButton_sim_beam.setObjectName("pushButton_sim_beam")
- self.gridLayout_4.addWidget(self.pushButton_sim_beam, 9, 1, 1, 1)
- self.label_sim_beam = QtWidgets.QLabel(self.frame_4)
- self.label_sim_beam.setObjectName("label_sim_beam")
- self.gridLayout_4.addWidget(self.label_sim_beam, 9, 0, 1, 1)
- self.label_options_title = QtWidgets.QLabel(self.frame_4)
- font = QtGui.QFont()
- font.setPointSize(10)
- font.setBold(True)
- font.setWeight(75)
- self.label_options_title.setFont(font)
- self.label_options_title.setObjectName("label_options_title")
- self.gridLayout_4.addWidget(self.label_options_title, 10, 0, 1, 1)
- self.lineEdit_pixel_size = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_pixel_size.setObjectName("lineEdit_pixel_size")
- self.gridLayout_4.addWidget(self.lineEdit_pixel_size, 3, 1, 1, 1)
- self.checkBox_save_plot = QtWidgets.QCheckBox(self.frame_4)
- self.checkBox_save_plot.setChecked(True)
- self.checkBox_save_plot.setObjectName("checkBox_save_plot")
- self.gridLayout_4.addWidget(self.checkBox_save_plot, 13, 1, 1, 1)
- self.lineEdit_sim_amplitude = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_sim_amplitude.setObjectName("lineEdit_sim_amplitude")
- self.gridLayout_4.addWidget(self.lineEdit_sim_amplitude, 8, 1, 1, 1)
- self.lineEdit_sim_name = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_sim_name.setObjectName("lineEdit_sim_name")
- self.gridLayout_4.addWidget(self.lineEdit_sim_name, 12, 1, 1, 1)
- self.label_sim_height = QtWidgets.QLabel(self.frame_4)
- self.label_sim_height.setObjectName("label_sim_height")
- self.gridLayout_4.addWidget(self.label_sim_height, 6, 0, 1, 1)
- self.label_pixel_size = QtWidgets.QLabel(self.frame_4)
- self.label_pixel_size.setObjectName("label_pixel_size")
- self.gridLayout_4.addWidget(self.label_pixel_size, 3, 0, 1, 1)
- self.lineEdit_sim_height = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_sim_height.setObjectName("lineEdit_sim_height")
- self.gridLayout_4.addWidget(self.lineEdit_sim_height, 6, 1, 1, 1)
- self.label_sim_num_stages = QtWidgets.QLabel(self.frame_4)
- self.label_sim_num_stages.setObjectName("label_sim_num_stages")
- self.gridLayout_4.addWidget(self.label_sim_num_stages, 15, 0, 1, 1)
- self.lineEdit_sim_wavelength = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_sim_wavelength.setObjectName("lineEdit_sim_wavelength")
- self.gridLayout_4.addWidget(self.lineEdit_sim_wavelength, 7, 1, 1, 1)
- self.lineEdit_log_dir = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_log_dir.setObjectName("lineEdit_log_dir")
- self.gridLayout_4.addWidget(self.lineEdit_log_dir, 11, 1, 1, 1)
- self.lineEdit_sim_width = QtWidgets.QLineEdit(self.frame_4)
- self.lineEdit_sim_width.setObjectName("lineEdit_sim_width")
- self.gridLayout_4.addWidget(self.lineEdit_sim_width, 5, 1, 1, 1)
- self.label_sim_name = QtWidgets.QLabel(self.frame_4)
- self.label_sim_name.setObjectName("label_sim_name")
- self.gridLayout_4.addWidget(self.label_sim_name, 12, 0, 1, 1)
- self.label_2 = QtWidgets.QLabel(self.frame_4)
- self.label_2.setObjectName("label_2")
- self.gridLayout_4.addWidget(self.label_2, 11, 0, 1, 1)
- self.gridLayout_5.addWidget(self.frame_4, 0, 0, 1, 1)
- self.scrollArea.setWidget(self.scrollAreaWidgetContents_2)
- self.gridLayout_3.addWidget(self.scrollArea, 1, 0, 1, 2)
- self.pushButton_generate_simulation = QtWidgets.QPushButton(self.frame_2)
- self.pushButton_generate_simulation.setObjectName("pushButton_generate_simulation")
- self.gridLayout_3.addWidget(self.pushButton_generate_simulation, 3, 0, 1, 2)
+ self.gridLayout_3.addWidget(self.spinBox_visualisation_scale, 8, 1, 1, 1)
+ self.label_visualisation_scale = QtWidgets.QLabel(self.frame_2)
+ self.label_visualisation_scale.setObjectName("label_visualisation_scale")
+ self.gridLayout_3.addWidget(self.label_visualisation_scale, 8, 0, 1, 1)
+ self.pushButton_visualise_simulation = QtWidgets.QPushButton(self.frame_2)
+ self.pushButton_visualise_simulation.setObjectName("pushButton_visualise_simulation")
+ self.gridLayout_3.addWidget(self.pushButton_visualise_simulation, 9, 0, 1, 2)
self.pushButton_setup_parameter_sweep = QtWidgets.QPushButton(self.frame_2)
self.pushButton_setup_parameter_sweep.setEnabled(False)
self.pushButton_setup_parameter_sweep.setObjectName("pushButton_setup_parameter_sweep")
- self.gridLayout_3.addWidget(self.pushButton_setup_parameter_sweep, 4, 0, 1, 2)
+ self.gridLayout_3.addWidget(self.pushButton_setup_parameter_sweep, 6, 0, 1, 2)
+ self.pushButton_generate_simulation = QtWidgets.QPushButton(self.frame_2)
+ self.pushButton_generate_simulation.setObjectName("pushButton_generate_simulation")
+ self.gridLayout_3.addWidget(self.pushButton_generate_simulation, 2, 0, 1, 2)
self.gridLayout_2.addWidget(self.frame_2, 0, 0, 1, 1)
- self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
+ self.gridLayout.addWidget(self.frame, 8, 0, 1, 1)
+ self.label = QtWidgets.QLabel(self.centralwidget)
+ self.label.setMaximumSize(QtCore.QSize(16777215, 200))
+ font = QtGui.QFont()
+ font.setPointSize(16)
+ font.setBold(True)
+ font.setWeight(75)
+ self.label.setFont(font)
+ self.label.setObjectName("label")
+ self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
+ spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout.addItem(spacerItem2, 9, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 408, 21))
@@ -192,43 +195,53 @@ def setupUi(self, MainWindow):
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
+ self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
+ MainWindow.setTabOrder(self.pushButton_visualise_simulation, self.lineEdit_pixel_size)
MainWindow.setTabOrder(self.lineEdit_pixel_size, self.lineEdit_sim_width)
MainWindow.setTabOrder(self.lineEdit_sim_width, self.lineEdit_sim_height)
MainWindow.setTabOrder(self.lineEdit_sim_height, self.lineEdit_sim_wavelength)
MainWindow.setTabOrder(self.lineEdit_sim_wavelength, self.lineEdit_sim_amplitude)
MainWindow.setTabOrder(self.lineEdit_sim_amplitude, self.pushButton_sim_beam)
MainWindow.setTabOrder(self.pushButton_sim_beam, self.lineEdit_log_dir)
- MainWindow.setTabOrder(self.lineEdit_log_dir, self.checkBox_save_plot)
- MainWindow.setTabOrder(self.checkBox_save_plot, self.spinBox_sim_num_stages)
+ MainWindow.setTabOrder(self.lineEdit_log_dir, self.lineEdit_sim_name)
+ MainWindow.setTabOrder(self.lineEdit_sim_name, self.checkBox_save_plot)
+ MainWindow.setTabOrder(self.checkBox_save_plot, self.tabWidget)
+ MainWindow.setTabOrder(self.tabWidget, self.spinBox_sim_num_stages)
MainWindow.setTabOrder(self.spinBox_sim_num_stages, self.scrollArea_stages)
+ MainWindow.setTabOrder(self.scrollArea_stages, self.pushButton_generate_simulation)
+ MainWindow.setTabOrder(self.pushButton_generate_simulation, self.pushButton_setup_parameter_sweep)
+ MainWindow.setTabOrder(self.pushButton_setup_parameter_sweep, self.spinBox_visualisation_scale)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
- self.label.setText(_translate("MainWindow", "Simulation Setup"))
- self.label_visualisation_scale.setText(_translate("MainWindow", "Downscale Visualisation Resolution"))
- self.label_sim_wavelength.setText(_translate("MainWindow", "Simulation Wavelength (m)"))
self.label_sim_amplitude.setText(_translate("MainWindow", "Simulation Amplitude"))
- self.label_stage_parameters_title.setText(_translate("MainWindow", "Stage Parameters"))
+ self.label_options_title.setText(_translate("MainWindow", "Simulation Options"))
self.label_sim_width.setText(_translate("MainWindow", "Simulation Width (m)"))
self.label_sim_param_title.setText(_translate("MainWindow", "Simulation Parameters"))
- self.pushButton_sim_beam.setText(_translate("MainWindow", "..."))
self.label_sim_beam.setText(_translate("MainWindow", "Simulation Beam"))
- self.label_options_title.setText(_translate("MainWindow", "Simulation Options"))
self.lineEdit_pixel_size.setText(_translate("MainWindow", "1e-6"))
+ self.label_sim_wavelength.setText(_translate("MainWindow", "Simulation Wavelength (m)"))
+ self.label_sim_name.setText(_translate("MainWindow", "Simulation Name"))
+ self.pushButton_sim_beam.setText(_translate("MainWindow", "..."))
+ self.label_2.setText(_translate("MainWindow", "Logging Directory"))
+ self.lineEdit_sim_width.setText(_translate("MainWindow", "1000e-6"))
self.checkBox_save_plot.setText(_translate("MainWindow", "Save Plots"))
- self.lineEdit_sim_amplitude.setText(_translate("MainWindow", "1"))
- self.label_sim_height.setText(_translate("MainWindow", "Simulation Height (m)"))
- self.label_pixel_size.setText(_translate("MainWindow", "Pixel Size (m)"))
self.lineEdit_sim_height.setText(_translate("MainWindow", "1000e-6"))
- self.label_sim_num_stages.setText(_translate("MainWindow", "Number of Stages"))
+ self.label_pixel_size.setText(_translate("MainWindow", "Pixel Size (m)"))
self.lineEdit_sim_wavelength.setText(_translate("MainWindow", "488.e-9"))
- self.lineEdit_sim_width.setText(_translate("MainWindow", "1000e-6"))
- self.label_sim_name.setText(_translate("MainWindow", "Simulation Name"))
- self.label_2.setText(_translate("MainWindow", "Logging Directory"))
- self.pushButton_generate_simulation.setText(_translate("MainWindow", "Generate Simulation"))
+ self.label_sim_height.setText(_translate("MainWindow", "Simulation Height (m)"))
+ self.lineEdit_sim_amplitude.setText(_translate("MainWindow", "1"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_simulation), _translate("MainWindow", "Simulation"))
+ self.label_sim_num_stages.setText(_translate("MainWindow", "Number of Stages"))
+ self.label_stage_parameters_title.setText(_translate("MainWindow", "Stage Parameters"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_stages), _translate("MainWindow", "Stages"))
+ self.label_visualisation_scale.setText(_translate("MainWindow", "Downscale Visualisation By"))
+ self.pushButton_visualise_simulation.setText(_translate("MainWindow", "Visualise Simulation"))
self.pushButton_setup_parameter_sweep.setText(_translate("MainWindow", "Setup Parameter Sweep"))
+ self.pushButton_generate_simulation.setText(_translate("MainWindow", "Generate Simulation"))
+ self.label.setText(_translate("MainWindow", "Simulation Setup"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionLoad_Configuration.setText(_translate("MainWindow", "Load Configuration"))
self.actionSave_Configuration.setText(_translate("MainWindow", "Save Configuration"))
diff --git a/juno/ui/qtdesigner_files/SimulationSetup.ui b/juno/ui/qtdesigner_files/SimulationSetup.ui
index 31cb417..372310e 100644
--- a/juno/ui/qtdesigner_files/SimulationSetup.ui
+++ b/juno/ui/qtdesigner_files/SimulationSetup.ui
@@ -15,7 +15,256 @@
- -
+
-
+
+
+ 0
+
+
+
+ Simulation
+
+
+
-
+
+
+ -
+
+
+ Simulation Amplitude
+
+
+
+ -
+
+
+
+ 10
+ 75
+ true
+
+
+
+ Simulation Options
+
+
+
+ -
+
+
+ Simulation Width (m)
+
+
+
+ -
+
+
+
+ 10
+ 75
+ true
+
+
+
+ Simulation Parameters
+
+
+
+ -
+
+
+ -
+
+
+ Simulation Beam
+
+
+
+ -
+
+
+ 1e-6
+
+
+
+ -
+
+
+ Simulation Wavelength (m)
+
+
+
+ -
+
+
+ Simulation Name
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ Logging Directory
+
+
+
+ -
+
+
+ 1000e-6
+
+
+
+ -
+
+
+ Save Plots
+
+
+ true
+
+
+
+ -
+
+
+ 1000e-6
+
+
+
+ -
+
+
+ Pixel Size (m)
+
+
+
+ -
+
+
+ 488.e-9
+
+
+
+ -
+
+
+ Simulation Height (m)
+
+
+
+ -
+
+
+ 1
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Maximum
+
+
+
+ 20
+ 60
+
+
+
+
+
+
+
+
+ Stages
+
+
+ -
+
+
+ Number of Stages
+
+
+
+ -
+
+
+ 1
+
+
+ 10
+
+
+ 1
+
+
+
+ -
+
+
+
+ 10
+ 75
+ true
+
+
+
+ Stage Parameters
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 364
+ 141
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+ -
QFrame::StyledPanel
@@ -54,34 +303,7 @@
QFrame::Raised
-
-
-
-
-
- 16777215
- 200
-
-
-
-
- 16
- 75
- true
-
-
-
- Simulation Setup
-
-
-
- -
-
-
- Downscale Visualisation Resolution
-
-
-
- -
+
-
1
@@ -91,260 +313,21 @@
- -
-
-
- true
+
-
+
+
+ Downscale Visualisation By
-
-
-
- 0
- 0
- 366
- 707
-
-
-
-
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- Simulation Wavelength (m)
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Maximum
-
-
-
- 20
- 60
-
-
-
-
- -
-
-
- Simulation Amplitude
-
-
-
- -
-
-
-
- 10
- 75
- true
-
-
-
- Stage Parameters
-
-
-
- -
-
-
- Simulation Width (m)
-
-
-
- -
-
-
- 1
-
-
- 10
-
-
- 1
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- true
-
-
-
-
- 0
- 0
- 326
- 184
-
-
-
-
-
- -
-
-
-
- 10
- 75
- true
-
-
-
- Simulation Parameters
-
-
-
- -
-
-
- ...
-
-
-
- -
-
-
- Simulation Beam
-
-
-
- -
-
-
-
- 10
- 75
- true
-
-
-
- Simulation Options
-
-
-
- -
-
-
- 1e-6
-
-
-
- -
-
-
- Save Plots
-
-
- true
-
-
-
- -
-
-
- 1
-
-
-
- -
-
-
- -
-
-
- Simulation Height (m)
-
-
-
- -
-
-
- Pixel Size (m)
-
-
-
- -
-
-
- 1000e-6
-
-
-
- -
-
-
- Number of Stages
-
-
-
- -
-
-
- 488.e-9
-
-
-
- -
-
-
- -
-
-
- 1000e-6
-
-
-
- -
-
-
- Simulation Name
-
-
-
- -
-
-
- Logging Directory
-
-
-
-
-
-
-
-
- -
-
+
-
+
- Generate Simulation
+ Visualise Simulation
- -
+
-
false
@@ -354,12 +337,52 @@
+ -
+
+
+ Generate Simulation
+
+
+
+ -
+
+
+
+ 16777215
+ 200
+
+
+
+
+ 16
+ 75
+ true
+
+
+
+ Simulation Setup
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ pushButton_visualise_simulation
lineEdit_pixel_size
lineEdit_sim_width
lineEdit_sim_height
@@ -400,9 +424,14 @@
lineEdit_sim_amplitude
pushButton_sim_beam
lineEdit_log_dir
+ lineEdit_sim_name
checkBox_save_plot
+ tabWidget
spinBox_sim_num_stages
scrollArea_stages
+ pushButton_generate_simulation
+ pushButton_setup_parameter_sweep
+ spinBox_visualisation_scale
diff --git a/juno/ui/qtdesigner_files/VisualiseResults.py b/juno/ui/qtdesigner_files/VisualiseResults.py
index 2c7b01f..7b82790 100644
--- a/juno/ui/qtdesigner_files/VisualiseResults.py
+++ b/juno/ui/qtdesigner_files/VisualiseResults.py
@@ -143,7 +143,16 @@ def setupUi(self, MainWindow):
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
- MainWindow.setTabOrder(self.pushButton_load_simulation, self.scroll_area_filter)
+ MainWindow.setTabOrder(self.pushButton_load_simulation, self.spinBox_num_filters)
+ MainWindow.setTabOrder(self.spinBox_num_filters, self.scroll_area_filter)
+ MainWindow.setTabOrder(self.scroll_area_filter, self.lineEdit_show_columns)
+ MainWindow.setTabOrder(self.lineEdit_show_columns, self.pushButton_reset_data)
+ MainWindow.setTabOrder(self.pushButton_reset_data, self.pushButton_filter_data)
+ MainWindow.setTabOrder(self.pushButton_filter_data, self.checkBox_log_plots)
+ MainWindow.setTabOrder(self.checkBox_log_plots, self.checkBox_show_all_simulations)
+ MainWindow.setTabOrder(self.checkBox_show_all_simulations, self.doubleSpinBox_scale)
+ MainWindow.setTabOrder(self.doubleSpinBox_scale, self.comboBox_napari_sim)
+ MainWindow.setTabOrder(self.comboBox_napari_sim, self.pushButton_update_visualisation)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
diff --git a/juno/ui/qtdesigner_files/VisualiseResults.ui b/juno/ui/qtdesigner_files/VisualiseResults.ui
index 103f9f6..b042fdb 100644
--- a/juno/ui/qtdesigner_files/VisualiseResults.ui
+++ b/juno/ui/qtdesigner_files/VisualiseResults.ui
@@ -276,7 +276,16 @@
pushButton_load_simulation
+ spinBox_num_filters
scroll_area_filter
+ lineEdit_show_columns
+ pushButton_reset_data
+ pushButton_filter_data
+ checkBox_log_plots
+ checkBox_show_all_simulations
+ doubleSpinBox_scale
+ comboBox_napari_sim
+ pushButton_update_visualisation
diff --git a/pyproject.toml b/pyproject.toml
index 249dc95..4e72b28 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,10 @@
[build-system]
-requires = [
- "setuptools>=42",
- "wheel"
-]
+requires = ["wheel", "setuptools>=45", "setuptools_scm[toml]>=6.2"]
build-backend = "setuptools.build_meta"
+[tool.setuptools_scm]
+write_to = "juno/_version.py"
+
[project]
name = "juno"
authors = [
diff --git a/setup.cfg b/setup.cfg
index 3d4ab29..b00f953 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,9 +1,9 @@
[metadata]
name = juno
-version = 0.0.1
+version = 0.1.0
author = David Dierickx, Patrick Cleeve
author_email = David.Dierickx1@monash.edu, Patrick.Cleeve@monash.edu
-description = juno is python package for designing lenses by performing full wave simulations.
+description = juno is python package for designing optical systems by performing full wave simulations.
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/DeMarcoLab/juno
@@ -16,7 +16,7 @@ classifiers =
[options]
packages = find:
-python_requires = >=3.8
+python_requires = >=3.7
[options.entry_points]
console_scripts =
diff --git a/tests/test_beam.py b/tests/test_beam.py
index eeac441..a8c8b52 100644
--- a/tests/test_beam.py
+++ b/tests/test_beam.py
@@ -252,6 +252,13 @@ def test_validate_beam_configuration(beam_settings):
with pytest.raises(ValueError):
validate_beam_configuration(settings)
+ # distance mode direct with step size greater than source distance
+ settings.distance_mode = DistanceMode.Direct
+ settings.source_distance = 1e-3
+ settings.step_size = 2e-3
+ with pytest.raises(ValueError):
+ validate_beam_configuration(settings)
+