Skip to content

Commit b98a49f

Browse files
committed
add ability to estimate probe photon count from diffraction data
1 parent 19e3e1d commit b98a49f

File tree

8 files changed

+147
-87
lines changed

8 files changed

+147
-87
lines changed

src/ptychodus/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def main() -> int:
132132

133133
from ptychodus.view import ViewCore
134134

135-
view = ViewCore.createInstance(parsedArgs.dev)
135+
view = ViewCore()
136136

137137
from ptychodus.controller import ControllerCore
138138

src/ptychodus/controller/core.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class ControllerCore:
2626
def __init__(self, model: ModelCore, view: ViewCore) -> None:
2727
self.view = view
2828

29-
self._memoryController = MemoryController(model.memoryPresenter, view.memoryProgressBar)
29+
self._memoryController = MemoryController(model.memoryPresenter, view.memory_progress_bar)
3030
self._fileDialogFactory = FileDialogFactory()
3131
self._ptyChiViewControllerFactory = PtyChiViewControllerFactory(
3232
model.ptyChiReconstructorLibrary
@@ -59,6 +59,7 @@ def __init__(self, model: ModelCore, view: ViewCore) -> None:
5959
self._fileDialogFactory,
6060
)
6161
self._productController = ProductController.createInstance(
62+
model.patterns_core.dataset,
6263
model.productRepository,
6364
model.productAPI,
6465
view.productView,
@@ -154,5 +155,5 @@ def showMainWindow(self, windowTitle: str) -> None:
154155

155156
def swapCentralWidgets(self, action: QAction) -> None:
156157
index = action.data()
157-
self.view.parametersWidget.setCurrentIndex(index)
158-
self.view.contentsWidget.setCurrentIndex(index)
158+
self.view.left_panel.setCurrentIndex(index)
159+
self.view.right_panel.setCurrentIndex(index)

src/ptychodus/controller/memory.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
from __future__ import annotations
2-
31
from PyQt5.QtCore import QTimer
4-
from PyQt5.QtWidgets import QProgressBar
2+
from PyQt5.QtWidgets import QProgressBar, QSizePolicy
53

64
from ..model.memory import MemoryPresenter
75

86

97
class MemoryController:
10-
def __init__(self, presenter: MemoryPresenter, progressBar: QProgressBar) -> None:
8+
def __init__(self, presenter: MemoryPresenter, progress_bar: QProgressBar) -> None:
119
self._presenter = presenter
12-
self._progressBar = progressBar
10+
self._progress_bar = progress_bar
11+
self._progress_bar.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
1312
self._timer = QTimer()
1413
self._timer.timeout.connect(self._updateProgressBar)
1514

@@ -24,6 +23,6 @@ def _updateProgressBar(self) -> None:
2423
availMemMB = int(stats.availableMemoryInBytes / 1e6)
2524
availMem = f'Available Memory: {availMemMB} MB'
2625

27-
self._progressBar.setRange(0, 100)
28-
self._progressBar.setValue(int(stats.memoryUsagePercent))
29-
self._progressBar.setToolTip('\n'.join((totalMem, availMem)))
26+
self._progress_bar.setRange(0, 100)
27+
self._progress_bar.setValue(int(stats.memoryUsagePercent))
28+
self._progress_bar.setToolTip('\n'.join((totalMem, availMem)))

src/ptychodus/controller/product/core.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
ProductRepositoryItem,
1919
ProductRepositoryObserver,
2020
)
21+
from ...model.patterns import AssembledDiffractionDataset
2122
from ...model.product.metadata import MetadataRepositoryItem
2223
from ...model.product.object import ObjectRepositoryItem
2324
from ...model.product.probe import ProbeRepositoryItem
@@ -150,6 +151,7 @@ def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
150151
class ProductController(ProductRepositoryObserver):
151152
def __init__(
152153
self,
154+
dataset: AssembledDiffractionDataset,
153155
repository: ProductRepository,
154156
api: ProductAPI,
155157
view: ProductView,
@@ -159,6 +161,7 @@ def __init__(
159161
tableProxyModel: QSortFilterProxyModel,
160162
) -> None:
161163
super().__init__()
164+
self._dataset = dataset
162165
self._repository = repository
163166
self._api = api
164167
self._view = view
@@ -170,6 +173,7 @@ def __init__(
170173
@classmethod
171174
def createInstance(
172175
cls,
176+
dataset: AssembledDiffractionDataset,
173177
repository: ProductRepository,
174178
api: ProductAPI,
175179
view: ProductView,
@@ -186,6 +190,7 @@ def createInstance(
186190
tableProxyModel.setSourceModel(tableModel)
187191

188192
controller = cls(
193+
dataset,
189194
repository,
190195
api,
191196
view,
@@ -290,7 +295,7 @@ def _editCurrentProduct(self) -> None:
290295

291296
if current.isValid():
292297
product = self._repository[current.row()]
293-
ProductEditorViewController.editProduct(product, self._view)
298+
ProductEditorViewController.editProduct(self._dataset, product, self._view)
294299
else:
295300
logger.error('No current item!')
296301

src/ptychodus/controller/product/editor.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
from typing import Any
22

33
from PyQt5.QtCore import (
4-
Qt,
54
QAbstractTableModel,
65
QModelIndex,
76
QObject,
87
QSortFilterProxyModel,
8+
Qt,
99
)
1010
from PyQt5.QtWidgets import QWidget
1111

1212
from ptychodus.api.observer import Observable, Observer
1313

14+
from ...model.patterns import AssembledDiffractionDataset
1415
from ...model.product import ProductRepositoryItem
1516
from ...view.product import ProductEditorDialog
1617

@@ -79,17 +80,21 @@ def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
7980
class ProductEditorViewController(Observer):
8081
def __init__(
8182
self,
83+
dataset: AssembledDiffractionDataset,
8284
product: ProductRepositoryItem,
8385
tableModel: ProductPropertyTableModel,
8486
dialog: ProductEditorDialog,
8587
) -> None:
8688
super().__init__()
89+
self._dataset = dataset
8790
self._product = product
8891
self._tableModel = tableModel
8992
self._dialog = dialog
9093

9194
@classmethod
92-
def editProduct(cls, product: ProductRepositoryItem, parent: QWidget) -> None:
95+
def editProduct(
96+
cls, dataset: AssembledDiffractionDataset, product: ProductRepositoryItem, parent: QWidget
97+
) -> None:
9398
tableModel = ProductPropertyTableModel(product)
9499
tableProxyModel = QSortFilterProxyModel()
95100
tableProxyModel.setSourceModel(tableModel)
@@ -102,11 +107,15 @@ def editProduct(cls, product: ProductRepositoryItem, parent: QWidget) -> None:
102107
dialog.tableView.resizeColumnsToContents()
103108
dialog.tableView.resizeRowsToContents()
104109

105-
viewController = cls(product, tableModel, dialog)
110+
viewController = cls(dataset, product, tableModel, dialog)
106111
product.addObserver(viewController)
107112
dialog.textEdit.textChanged.connect(viewController._syncViewToModel)
108113

109114
viewController._syncModelToView()
115+
116+
dialog.actionsView.estimateProbePhotonCountButton.clicked.connect(
117+
viewController._estimateProbePhotonCount
118+
)
110119
dialog.finished.connect(viewController._finish)
111120
dialog.open()
112121
dialog.adjustSize()
@@ -122,6 +131,13 @@ def _syncModelToView(self) -> None:
122131
metadata = self._product.getMetadata()
123132
self._dialog.textEdit.setPlainText(metadata.comments.getValue())
124133

134+
def _estimateProbePhotonCount(self) -> None:
135+
metadata = self._product.getMetadata()
136+
metadata.probePhotonCount.setValue(self._dataset.get_maximum_pattern_counts())
137+
138+
self._tableModel.beginResetModel()
139+
self._tableModel.endResetModel()
140+
125141
def _finish(self, result: int) -> None:
126142
self._product.removeObserver(self)
127143

src/ptychodus/controller/scan/core.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33

44
from PyQt5.QtCore import QModelIndex, QSortFilterProxyModel, QStringListModel
5-
from PyQt5.QtWidgets import QAbstractItemView, QDialog
5+
from PyQt5.QtWidgets import QAbstractItemView, QDialog, QMessageBox
66

77
from ptychodus.api.observer import SequenceObserver
88

@@ -93,6 +93,9 @@ def createInstance(
9393

9494
view.buttonBox.editButton.clicked.connect(controller._editCurrentScan)
9595

96+
estimateTransformAction = view.buttonBox.analyzeMenu.addAction('Estimate Transform...')
97+
estimateTransformAction.triggered.connect(controller._estimateTransform)
98+
9699
return controller
97100

98101
def _getCurrentItemIndex(self) -> int:
@@ -203,6 +206,19 @@ def _redrawPlot(self) -> None:
203206

204207
self._plotView.figureCanvas.draw()
205208

209+
def _estimateTransform(self) -> None: # FIXME
210+
itemIndex = self._getCurrentItemIndex()
211+
212+
if itemIndex < 0:
213+
logger.warning('No current item!')
214+
return
215+
216+
_ = QMessageBox.information(
217+
self._view,
218+
'Not Implemented',
219+
'Affine transform estimator is not yet implemented.',
220+
)
221+
206222
def _updateView(self, current: QModelIndex, previous: QModelIndex) -> None:
207223
enabled = current.isValid()
208224
self._view.buttonBox.loadButton.setEnabled(enabled)

src/ptychodus/view/core.py

Lines changed: 46 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,19 @@
3131

3232

3333
class ViewCore(QMainWindow):
34-
def __init__(self, parent: QWidget | None) -> None:
34+
def __init__(self, parent: QWidget | None = None) -> None:
3535
super().__init__(parent)
3636

37+
logger.info(f'PyQt {PYQT_VERSION_STR}')
38+
logger.info(f'Qt {QT_VERSION_STR}')
39+
3740
self.navigationToolBar = QToolBar()
3841
self.navigationActionGroup = QActionGroup(self.navigationToolBar)
3942

4043
self.splitter = QSplitter(Qt.Orientation.Horizontal)
41-
self.parametersWidget = QStackedWidget()
42-
self.contentsWidget = QStackedWidget()
43-
self.memoryProgressBar = QProgressBar()
44+
self.left_panel = QStackedWidget()
45+
self.right_panel = QStackedWidget()
46+
self.memory_progress_bar = QProgressBar()
4447

4548
self.settingsAction = self.navigationToolBar.addAction(
4649
QIcon(':/icons/settings'), 'Settings'
@@ -88,68 +91,51 @@ def __init__(self, parent: QWidget | None) -> None:
8891
self.automationView = AutomationView.createInstance()
8992
self.automationWidget = QWidget()
9093

91-
@classmethod
92-
def createInstance(
93-
cls, isDeveloperModeEnabled: bool, parent: QWidget | None = None
94-
) -> ViewCore:
95-
logger.info(f'PyQt {PYQT_VERSION_STR}')
96-
logger.info(f'Qt {QT_VERSION_STR}')
94+
#####
9795

98-
view = cls(parent)
99-
view.setWindowIcon(QIcon(':/icons/ptychodus'))
96+
self.setWindowIcon(QIcon(':/icons/ptychodus'))
10097

101-
view.navigationToolBar.setContextMenuPolicy(Qt.ContextMenuPolicy.PreventContextMenu)
102-
view.addToolBar(Qt.ToolBarArea.LeftToolBarArea, view.navigationToolBar)
103-
view.navigationToolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
104-
view.navigationToolBar.setIconSize(QSize(32, 32))
98+
self.navigationToolBar.setContextMenuPolicy(Qt.ContextMenuPolicy.PreventContextMenu)
99+
self.navigationToolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
100+
self.navigationToolBar.setIconSize(QSize(32, 32))
101+
self.addToolBar(Qt.ToolBarArea.LeftToolBarArea, self.navigationToolBar)
105102

106-
for index, action in enumerate(view.navigationToolBar.actions()):
103+
for index, action in enumerate(self.navigationToolBar.actions()):
107104
action.setCheckable(True)
108105
action.setData(index)
109-
view.navigationActionGroup.addAction(action)
106+
self.navigationActionGroup.addAction(action)
110107

111108
# maintain same order as navigationToolBar buttons
112-
view.parametersWidget.addWidget(view.settingsView)
113-
view.parametersWidget.addWidget(view.patternsView)
114-
view.parametersWidget.addWidget(view.productView)
115-
view.parametersWidget.addWidget(view.scanView)
116-
view.parametersWidget.addWidget(view.probeView)
117-
view.parametersWidget.addWidget(view.objectView)
118-
view.parametersWidget.addWidget(view.reconstructorView)
119-
view.parametersWidget.addWidget(view.workflowParametersView)
120-
view.parametersWidget.addWidget(view.automationView)
121-
view.parametersWidget.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
122-
view.splitter.addWidget(view.parametersWidget)
109+
self.left_panel.addWidget(self.settingsView)
110+
self.left_panel.addWidget(self.patternsView)
111+
self.left_panel.addWidget(self.productView)
112+
self.left_panel.addWidget(self.scanView)
113+
self.left_panel.addWidget(self.probeView)
114+
self.left_panel.addWidget(self.objectView)
115+
self.left_panel.addWidget(self.reconstructorView)
116+
self.left_panel.addWidget(self.workflowParametersView)
117+
self.left_panel.addWidget(self.automationView)
118+
self.left_panel.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
119+
self.splitter.addWidget(self.left_panel)
123120

124121
# maintain same order as navigationToolBar buttons
125-
view.contentsWidget.addWidget(view.settingsTableView)
126-
view.contentsWidget.addWidget(view.patternsImageView)
127-
view.contentsWidget.addWidget(view.productDiagramView)
128-
view.contentsWidget.addWidget(view.scanPlotView)
129-
view.contentsWidget.addWidget(view.probeImageView)
130-
view.contentsWidget.addWidget(view.objectImageView)
131-
view.contentsWidget.addWidget(view.reconstructorPlotView)
132-
view.contentsWidget.addWidget(view.workflowTableView)
133-
view.contentsWidget.addWidget(view.automationWidget)
134-
view.contentsWidget.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
135-
view.splitter.addWidget(view.contentsWidget)
136-
137-
view.setCentralWidget(view.splitter)
138-
139-
# TODO make visible when complete
140-
view.scanView.buttonBox.analyzeButton.setVisible(isDeveloperModeEnabled)
141-
view.probeView.buttonBox.analyzeButton.setVisible(isDeveloperModeEnabled)
142-
view.objectView.buttonBox.analyzeButton.setVisible(isDeveloperModeEnabled)
143-
144-
desktopSize = QApplication.desktop().availableGeometry().size()
145-
preferredHeight = desktopSize.height() * 2 // 3
146-
preferredWidth = min(desktopSize.width() * 2 // 3, 2 * preferredHeight)
147-
view.resize(preferredWidth, preferredHeight)
148-
149-
view.memoryProgressBar.setSizePolicy(
150-
QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred
151-
)
152-
view.statusBar().addPermanentWidget(view.memoryProgressBar)
153-
view.statusBar().showMessage('Ready')
154-
155-
return view
122+
self.right_panel.addWidget(self.settingsTableView)
123+
self.right_panel.addWidget(self.patternsImageView)
124+
self.right_panel.addWidget(self.productDiagramView)
125+
self.right_panel.addWidget(self.scanPlotView)
126+
self.right_panel.addWidget(self.probeImageView)
127+
self.right_panel.addWidget(self.objectImageView)
128+
self.right_panel.addWidget(self.reconstructorPlotView)
129+
self.right_panel.addWidget(self.workflowTableView)
130+
self.right_panel.addWidget(self.automationWidget)
131+
self.right_panel.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
132+
self.splitter.addWidget(self.right_panel)
133+
134+
self.setCentralWidget(self.splitter)
135+
136+
desktop_size = QApplication.desktop().availableGeometry().size()
137+
preferred_height = desktop_size.height() * 2 // 3
138+
preferred_width = min(desktop_size.width() * 2 // 3, 2 * preferred_height)
139+
self.resize(preferred_width, preferred_height)
140+
141+
self.statusBar().addPermanentWidget(self.memory_progress_bar)

0 commit comments

Comments
 (0)