Commit 2ff8dd71 authored by Josef Brandt's avatar Josef Brandt

Basic Acquisition

parent 405a0850
...@@ -26,3 +26,5 @@ ramancom/renishawtesting.py ...@@ -26,3 +26,5 @@ ramancom/renishawtesting.py
*.obj *.obj
*.pyc *.pyc
*.jdx
...@@ -373,7 +373,7 @@ if __name__ == '__main__': ...@@ -373,7 +373,7 @@ if __name__ == '__main__':
logging.handlers.RotatingFileHandler( logging.handlers.RotatingFileHandler(
logname, maxBytes=5*(1 << 20), backupCount=10) logname, maxBytes=5*(1 << 20), backupCount=10)
) )
logger.setLevel(logging.DEBUG)
setDefaultLoggingConfig(logger) setDefaultLoggingConfig(logger)
logger.info("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime())) logger.info("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()))
......
...@@ -128,7 +128,8 @@ class Measurement(object): ...@@ -128,7 +128,8 @@ class Measurement(object):
self.assignment_orig = 'Not Evaluated' self.assignment_orig = 'Not Evaluated'
self.assignment_afterHQI = None self.assignment_afterHQI = None
self.hqi = 0 self.hqi = 0
self.measurementResults: dict = {}
self.assignedParticle = None self.assignedParticle = None
def setAssignment(self, assignment): def setAssignment(self, assignment):
......
...@@ -34,15 +34,15 @@ class ParticleContainer(object): ...@@ -34,15 +34,15 @@ class ParticleContainer(object):
self.measurements = [] self.measurements = []
self.inconsistentParticles = [] self.inconsistentParticles = []
def addEmptyMeasurement(self): def addEmptyMeasurement(self) -> int:
newMeas = Measurement() newMeas = Measurement()
self.measurements.append(newMeas) self.measurements.append(newMeas)
return self.measurements.index(newMeas) return self.measurements.index(newMeas)
def clearParticles(self): def clearParticles(self) -> None:
self.particles = [] self.particles = []
def clearMeasurements(self): def clearMeasurements(self) -> None:
self.measurements = [] self.measurements = []
for particle in self.particles: for particle in self.particles:
particle.measurements = [] particle.measurements = []
...@@ -132,6 +132,13 @@ class ParticleContainer(object): ...@@ -132,6 +132,13 @@ class ParticleContainer(object):
for meas in self.measurements: for meas in self.measurements:
scanIndex = meas.getScanIndex() scanIndex = meas.getScanIndex()
meas.setAssignment(assignmentList[scanIndex]) meas.setAssignment(assignmentList[scanIndex])
def applyDatabaseResultsToParticleMeasurements(self, resultDictList: list) -> None:
"""
The resultDictList has a dict for each measurement, containing multiple database results.
Key: HQI, Val: Resultname
"""
pass
def applyHQIListToParticleMeasurements(self, hqiList): def applyHQIListToParticleMeasurements(self, hqiList):
'''HQI-List is list of spectra hqis in order of spectra indices''' '''HQI-List is list of spectra hqis in order of spectra indices'''
......
...@@ -169,7 +169,11 @@ class DataSet(object): ...@@ -169,7 +169,11 @@ class DataSet(object):
if newProject: if newProject:
self.fname = self.newProject(fname) self.fname = self.newProject(fname)
self.updatePath() self.updatePath()
@property
def opticalScanDone(self) -> bool:
return os.path.exists(self.getZvalImageName())
def __eq__(self, other): def __eq__(self, other):
return recursiveDictCompare(self.__dict__, other.__dict__) return recursiveDictCompare(self.__dict__, other.__dict__)
......
...@@ -52,7 +52,7 @@ def scan(path, sol, zpositions, grid, controlclass, dataqueue, ...@@ -52,7 +52,7 @@ def scan(path, sol, zpositions, grid, controlclass, dataqueue,
try: try:
ramanctrl = controlclass(logger) ramanctrl = controlclass(logger)
ramanctrl.setupToDatasetPath(os.path.dirname(logpath)) ramanctrl.updateImageConfig(os.path.dirname(logpath))
ramanctrl.connect() ramanctrl.connect()
zlist = list(enumerate(zpositions)) zlist = list(enumerate(zpositions))
for i, p in enumerate(grid): for i, p in enumerate(grid):
...@@ -354,7 +354,7 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -354,7 +354,7 @@ class OpticalScan(QtWidgets.QWidget):
self.pexit = QtWidgets.QPushButton("Cancel", self) self.pexit = QtWidgets.QPushButton("Cancel", self)
self.pareaselect.released.connect(self.areaSelect) self.pareaselect.released.connect(self.areaSelect)
self.prun.released.connect(self.run) self.prun.released.connect(self.run)
self.pexit.released.connect(self.stopScan) self.pexit.released.connect(self.cancelScan)
self.prun.setEnabled(False) self.prun.setEnabled(False)
self.progressbar = TimeEstimateProgressbar() self.progressbar = TimeEstimateProgressbar()
...@@ -449,7 +449,7 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -449,7 +449,7 @@ class OpticalScan(QtWidgets.QWidget):
self.adjustSize() self.adjustSize()
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def stopScan(self): def cancelScan(self):
if self.process is not None and self.process.is_alive(): if self.process is not None and self.process.is_alive():
reply = QtWidgets.QMessageBox.question(self, 'Stop optical scan?', reply = QtWidgets.QMessageBox.question(self, 'Stop optical scan?',
"Do you want to terminate the running scan?", "Do you want to terminate the running scan?",
...@@ -459,15 +459,13 @@ class OpticalScan(QtWidgets.QWidget): ...@@ -459,15 +459,13 @@ class OpticalScan(QtWidgets.QWidget):
self.progressbar.resetTimerAndCounter() self.progressbar.resetTimerAndCounter()
self.timer.stop() self.timer.stop()
self.processstopevent.set() self.processstopevent.set()
self.process.terminate()
self.process.join() self.process.join()
self.dataqueue.close() self.dataqueue.close()
self.dataqueue.join_thread() self.dataqueue.join_thread()
self.view.unblockUI() self.view.unblockUI()
else: self.close()
return
self.close()
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def areaSelect(self): def areaSelect(self):
magn = self.ramanctrl.magn magn = self.ramanctrl.magn
......
...@@ -254,11 +254,11 @@ class WITecCOM(RamanBase): ...@@ -254,11 +254,11 @@ class WITecCOM(RamanBase):
self.BeamPathSetVideoState = win32com.client.CastTo(self.BeamPathSetVideoStateInterface, 'IBUCSTrigger') self.BeamPathSetVideoState = win32com.client.CastTo(self.BeamPathSetVideoStateInterface, 'IBUCSTrigger')
try: try:
from .advancedWITec import AdvancedWITecSpectra from .spechandler import SpectraAcquisition
except ModuleNotFoundError: except ModuleNotFoundError:
from advancedWITec import AdvancedWITecSpectra from spechandler import SpectraAcquisition
self.advSpec = AdvancedWITecSpectra() self.advSpec = SpectraAcquisition(self)
if 'Autofocus' not in [param.name for param in self.ramanParameters]: if 'Autofocus' not in [param.name for param in self.ramanParameters]:
self.ramanParameters.append(RamanSettingParam('Autofocus', 'checkBox', default=False)) self.ramanParameters.append(RamanSettingParam('Autofocus', 'checkBox', default=False))
self.ramanParameters.append(RamanSettingParam('Spectra Batch Size', 'int', default=1000, minVal=1, maxVal=1e6)) self.ramanParameters.append(RamanSettingParam('Spectra Batch Size', 'int', default=1000, minVal=1, maxVal=1e6))
...@@ -390,16 +390,17 @@ class WITecCOM(RamanBase): ...@@ -390,16 +390,17 @@ class WITecCOM(RamanBase):
width, height = self.ImageWidthMan.GetValue(), self.ImageHeightMan.GetValue() width, height = self.ImageWidthMan.GetValue(), self.ImageHeightMan.GetValue()
angle = self.ImageRotationMan.GetValue() angle = self.ImageRotationMan.GetValue()
return width, height, angle return width, height, angle
def startSinglePointScan(self): # IT IS NOT NEEDED, ISN'T IT??
assert self.connected # def startSinglePointScan(self):
self.SequencerStartTrigger.OperateTrigger() # assert self.connected
# Wait until sequencer has finished # self.SequencerStartTrigger.OperateTrigger()
while True: # # Wait until sequencer has finished
self.SequencerBusyStatus.Update() # while True:
Busy = self.SequencerBusyStatus.GetSingleValueAsInt()[1] # self.SequencerBusyStatus.Update()
if not Busy: # Busy = self.SequencerBusyStatus.GetSingleValueAsInt()[1]
break # if not Busy:
# break
####TODO: should the below methods also get the comErrorRepeater?? Repeating these commands could mess up something... ####TODO: should the below methods also get the comErrorRepeater?? Repeating these commands could mess up something...
...@@ -458,7 +459,7 @@ class WITecCOM(RamanBase): ...@@ -458,7 +459,7 @@ class WITecCOM(RamanBase):
self.doAutoFocus = ramanSettings['Autofocus'] self.doAutoFocus = ramanSettings['Autofocus']
self.advSpec.createTmpSpecFolder() # self.advSpec.createTmpSpecFolder()
state = self.BeamPathState.GetValue() state = self.BeamPathState.GetValue()
if state == 'Video': if state == 'Video':
self.MicroscopeIdle.SetValue('BeamPath|SetStateRaman') self.MicroscopeIdle.SetValue('BeamPath|SetStateRaman')
......
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
from time import sleep
try:
from ..errors import showErrorMessageAsWidget
except (ValueError, ImportError):
from errors import showErrorMessageAsWidget
def comErrorRepeater(comCallFunction):
"""
A wrapper function for handling rarely occuring dde errors.
If a dee error occurs, a sleep time of one second is done, than the function is repeated.
This is done three times. If still no success was achieved, the com interface is reconnected
and, again, the function is started three times at maximum.
If none of this worked, an error message is shown and an exception is raised.
Parameters
----------
comCallFunction : function object
The function to apply the wrapper to.
Returns
-------
wrapper : function object
The wrapped function
"""
def wrapper(*args, **kwargs):
def tryFunctionThreeTimes(c):
success = False
for _ in range(3):
curResult = None
c += 1
try:
curResult = comCallFunction(*args, **kwargs)
success = True
break
except Exception as exc:
comObj.logger.warning(
f'Unsuccessful {c}. attempt for COM call of function {comCallFunction.__name__}\n{type(exc)}'
)
sleep(1.)
return success, curResult, c
c = 0
comObj = args[0] # self is always passed as first argument
functionSucceeded, result, c = tryFunctionThreeTimes(c)
if not functionSucceeded:
comObj.logger.warning(f'Reconnecting for function {comCallFunction.__name__}')
comObj.disconnect()
sleep(1.)
comObj.connect()
functionSucceeded, result, c = tryFunctionThreeTimes(c)
if not functionSucceeded:
comObj.logger.warning(f'COM error: function {comCallFunction.__name__} could not be executed')
showErrorMessageAsWidget(f'COM error on function {comCallFunction.__name__}')
raise Exception
return result
return wrapper
\ No newline at end of file
...@@ -19,12 +19,13 @@ along with this program, see COPYING. ...@@ -19,12 +19,13 @@ along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>. If not, see <https://www.gnu.org/licenses/>.
""" """
class RamanBase(object): class RamanBase(object):
def __init__(self, logger=None): def __init__(self, logger=None):
self.name = None self.name = None
self.connected = False self.connected = False
self.timeseries = False self.timeseries = False
self.logger = None self.logger = logger
def getRamanPositionShift(self): def getRamanPositionShift(self):
""" Compute the shift between laser spot and image center""" """ Compute the shift between laser spot and image center"""
...@@ -55,13 +56,14 @@ class RamanBase(object): ...@@ -55,13 +56,14 @@ class RamanBase(object):
def saveImage(self, fname): def saveImage(self, fname):
raise NotImplementedError raise NotImplementedError
def getImageDimensions(self, mode = 'df'): def getImageDimensions(self, mode: str = 'df'):
""" Get the image width and height in um and the orientation angle in degrees. """ Get the image width and height in um and the orientation angle in degrees.
""" """
raise NotImplementedError raise NotImplementedError
def startSinglePointScan(self): # IT IS NOT NEEDED, ISN'T IT??
raise NotImplementedError # def startSinglePointScan(self):
# raise NotImplementedError
def initiateMeasurement(self, ramanSettings): def initiateMeasurement(self, ramanSettings):
raise NotImplementedError raise NotImplementedError
...@@ -72,10 +74,10 @@ class RamanBase(object): ...@@ -72,10 +74,10 @@ class RamanBase(object):
def finishMeasurement(self, aborted=False): def finishMeasurement(self, aborted=False):
raise NotImplementedError raise NotImplementedError
def setupToDatasetPath(self, dsetpath: str) -> None: def updateImageConfig(self, dsetpath: str) -> None:
""" """
Can be overloaded if the ramancontrol needs to know where the current project is located Can be overloaded if the ramancontrol needs to update image config fro dataset folder
:param dsetpath: filepath to the dataset, i.e. the :param dsetpath: filepath to the dataset
:return: :return:
""" """
pass pass
\ No newline at end of file
...@@ -28,9 +28,11 @@ import numpy as np ...@@ -28,9 +28,11 @@ import numpy as np
from shutil import copyfile from shutil import copyfile
from .ramanbase import RamanBase from .ramanbase import RamanBase
class SimulatedRaman(RamanBase): class SimulatedRaman(RamanBase):
magn = 20 magn = 20
ramanParameters = {} ramanParameters = {}
def __init__(self, logger): def __init__(self, logger):
super().__init__() super().__init__()
self.name = 'SimulatedRaman' self.name = 'SimulatedRaman'
...@@ -38,11 +40,11 @@ class SimulatedRaman(RamanBase): ...@@ -38,11 +40,11 @@ class SimulatedRaman(RamanBase):
self.currentpos = None, 0., 0. self.currentpos = None, 0., 0.
self.currentZ = 0. self.currentZ = 0.
# some plausible data to simulate consecutively changing positions # some plausible data to simulate consecutively changing positions
self.positionlist = np.array([[ -1201, 1376, -1290], self.positionlist = np.array([[-1201, 1376, -1290],
[ -1195, -1200, -1279], [-1195, -1200, -1279],
[ 1097, -1254, -1297], [1097, -1254, -1297],
[ 2704.1, 1288.2, -1381], [2704.1, 1288.2, -1381],
[ 1884. , -1500.8, -1381]]) [1884., -1500.8, -1381]])
self.znum = 4 self.znum = 4
self.gridnum = 36 self.gridnum = 36
self.positionindex = 0 self.positionindex = 0
...@@ -106,19 +108,19 @@ class SimulatedRaman(RamanBase): ...@@ -106,19 +108,19 @@ class SimulatedRaman(RamanBase):
assert self.connected assert self.connected
width, height, angle = 463.78607177734375, 296.0336608886719, -0.04330849274992943 width, height, angle = 463.78607177734375, 296.0336608886719, -0.04330849274992943
return width, height, angle return width, height, angle
def startSinglePointScan(self): # IT IS NOT NEEDED, ISN'T IT??
assert self.connected # def startSinglePointScan(self):
self.logger.info("Fake scan") # assert self.connected
sleep(.3) # self.logger.info("Fake scan")
# sleep(.3)
def initiateMeasurement(self, ramanSettings): def initiateMeasurement(self, ramanSettings):
assert self.connected assert self.connected
self.logger.info(f"Scanning {ramanSettings['numPoints']} particle positions") self.logger.info(f"Scanning {ramanSettings['numPoints']} particle positions")
self.timeseries = ramanSettings['numPoints'] self.timeseries = ramanSettings['numPoints']
sleep(.1) sleep(.1)
def triggerMeasurement(self, num): def triggerMeasurement(self, num):
assert self.timeseries assert self.timeseries
self.logger.info(f"Scan number: {num}") self.logger.info(f"Scan number: {num}")
......
...@@ -21,50 +21,207 @@ If not, see <https://www.gnu.org/licenses/>. ...@@ -21,50 +21,207 @@ If not, see <https://www.gnu.org/licenses/>.
import os import os
import numpy as np import numpy as np
class AdvancedWITecSpectra(object):
class SpectraHandler(object):
""" """
Handles Spectra formatting and storage when using the advanced "silent spectrum" option in the WITec COM interface Handles Spectra formatting and storage.
:return: :return:
""" """
def __init__(self): def __init__(self, ramanctrl):
super(AdvancedWITecSpectra, self).__init__() super(SpectraHandler, self).__init__()
self.ramanctrlname = ramanctrl.name
self.dsetpath = None self.dsetpath = None
self.tmpspecpath = None self.tmpspecpath = None
self.curSpecIndex = None self.curSpecIndex = None
self.excitWavel = None
self.spectraBatchSize = None self.spectraBatchSize = None
self.wavenumbers: np.ndarray = None
if ramanctrl.name == 'WITecCOM':
self.specConverter = WITecSpecConverter()
else:
self.specConverter = None
def setDatasetPath(self, path): def setDatasetPath(self, path):
self.dsetpath = path self.dsetpath = path
self.createTmpSpecFolder()
def setSpectraBatchSize(self, batchSize): def setSpectraBatchSize(self, batchSize):
self.spectraBatchSize = batchSize self.spectraBatchSize = batchSize
def createTmpSpecFolder(self): def createTmpSpecFolder(self):
assert self.dsetpath is not None assert self.dsetpath is not None
self.tmpspecpath = os.path.join(self.dsetpath, 'spectra') self.tmpspecpath = os.path.join(self.dsetpath, 'spectra')
if not os.path.exists(self.tmpspecpath): if not os.path.exists(self.tmpspecpath):
os.mkdir(self.tmpspecpath) os.mkdir(self.tmpspecpath)
def registerNewSpectrum(self, specString, specIndex): def registerBackground(self, backgroundid: int, spec: np.ndarray) -> None:
wavenumbers, averaged_counts = self.deassembleSpecString(specString) fname: str = self.getPathForBackroundOfID(backgroundid)
spec = self.mapSpecToWavenumbers(spec)
np.save(fname, spec)
def getBackGroundOfID(self, id: int) -> np.ndarray:
path: str = self.getPathForBackroundOfID(id)
assert os.path.exists(path), f'requested backgound file {path} does not exist!'
return np.load(path)
def registerNewSpectrum(self, spectrum, specIndex: int, deassamble: bool = False):
assert self.tmpspecpath is not None, 'Attempting to save spectrum but no specPath is set...'
if deassamble:
wavenumbers, intensities = self.specConverter.deassembleSpecString(spectrum)
else:
assert type(spectrum) == np.ndarray
wavenumbers, intensities = spectrum[:, 0], spectrum[:, 1]
if not np.all(np.isfinite(spectrum)):
spectrum = self.makeSpecFinite(spectrum)
if specIndex == 0: if specIndex == 0:
fname = os.path.join(self.tmpspecpath, 'Wavenumbers.npy') np.save(self.getPathForWavenumbers(), wavenumbers)
np.save(fname, wavenumbers)
fname = os.path.join(self.tmpspecpath, f'Spectrum ({specIndex}).npy') fname = os.path.join(self.tmpspecpath, f'Spectrum ({specIndex}).npy')
np.save(fname, averaged_counts) np.save(fname, intensities)
self.curSpecIndex = specIndex self.curSpecIndex = specIndex
def createSummarizedSpecFiles(self): def createSummarizedSpecFiles(self):
allSpectra = self.getAllSpectra() allSpectra = self.getAllSpectra()
allspecfname = os.path.join(self.dsetpath, 'spectra.npy') allspecfname = os.path.join(self.dsetpath, 'spectra.npy')
np.save(allspecfname, allSpectra) np.save(allspecfname, allSpectra)
self.createTrueMatchTxt(allSpectra, self.excitWavel) wavelength: float = (self.specConverter.excitWavel if self.specConverter is not None else 0.0)
self.createTrueMatchTxt(allSpectra, wavelength)
def deassembleSpecString(self, specString):
def getAllSpectra(self):
numSpectra = self.curSpecIndex + 1
wavenumbers = np.load(os.path.join(self.tmpspecpath, 'Wavenumbers.npy'))
allSpectra = np.zeros((wavenumbers.shape[0], numSpectra+1))
allSpectra[:, 0] = wavenumbers
for i in range(numSpectra):
curSpecPath = os.path.join(self.tmpspecpath, f'Spectrum ({i}).npy')
allSpectra[:, i+1] = np.load(curSpecPath)
os.remove(curSpecPath)
return allSpectra
def createTrueMatchTxt(self, allSpectra, wavelength):
def writeHeader(fp):
fp.write('[WITEC_TRUEMATCH_ASCII_HEADER]\n\r')
fp.write('Version = 2.0\n\r\n\r')
def writeWavenumbers(fp, wavenumbers):
fp.write('[XData]\n\r')
for line in wavenumbers:
fp.write(str(line) + '\n\r')
def writeSpectrum(fp, intensities):
fp.write('\n\r')
fp.write('[SpectrumHeader]\n\r')
fp.write(f'Title = Spectrum {specIndex} \n\r')
fp.write(f'ExcitationWavelength = {wavelength}\n\r')
fp.write(f'SpectrumSize = {specSize}\n\r')
fp.write('XDataKind = 1/cm\n\r\n\r')
fp.write('[SampleMetaData]\n\r')
fp.write(f'int Spectrum_Number = {specIndex}\n\r\n\r')
fp.write('[SpectrumData]\n\r')
for line in intensities:
fp.write(str(line) + '\n\r')
wavenumbers = allSpectra[:, 0]
spectra = allSpectra<