DTObs.py 10.7 KB
Newer Older
1
2
3
4
5
#!/usr/bin/env python3

import sys
import csv
import logging
6
from configparser import ConfigParser
7
8
9
import subprocess
import traceback
import time
10
import os.path
11
12
13
14
15
16
17
18
19
import numpy as np

from PyQt5 import QtGui
from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, pyqtSlot, QThreadPool
from PyQt5.QtWidgets import (QFileDialog, QApplication, QMainWindow, QTableWidgetItem)
from ui.dtobswindow import Ui_mainWindow

from astropy import units as u
from astropy.coordinates import SkyCoord
20

marc's avatar
marc committed
21
22
23
24
from telescope import telescope
from measurements import Measurements
from metadata import MetaData

25
'''
marc's avatar
marc committed
26
Setup config ini
27
28
29
'''
config = ConfigParser()
config.readfp(open(os.path.join(os.path.dirname(__file__), 'dtobsgui.ini')))
marc's avatar
marc committed
30
31
32
33
34
35
36
37

'''
Setup logging
'''
logger = logging.getLogger('root')
FORMAT = "[%(asctime)s%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s,filename='dtobsgui.log',filemode='w'"
logging.basicConfig(format=FORMAT)
logger.setLevel(logging.DEBUG)
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

class WorkerSignals(QObject):
    """
    Defines the signals available from a running worker thread.

    Supported signals are:

    finished
        `int` of the setpoint number

    error
        `tuple` (exctype, value, traceback.format_exc() )

    result
        `object` data returned from processing, anything

    progress
        `int` inicating % progress
    """

    finished = pyqtSignal(int, str)
    allfinished = pyqtSignal()
    # error = pyqtSignal(tuple)
    # result = pyqtSignal(object)
    progress = pyqtSignal(int, int, str) # meas_num, percent_complete, remaining

class Worker(QRunnable):
    """ Execute a function asynchronously, connect to signals """

    def __init__(self, function_to_run, *args, **kwargs):
        super(Worker, self).__init__()
        # Store arguments
        self.function_to_run = function_to_run
        self.args = args
        self.kwargs = kwargs
        self.signals = WorkerSignals()

        self.kwargs['oneSetpointCompleteSignal'] = self.signals.finished
        self.kwargs['progressSignal'] = self.signals.progress

    @pyqtSlot()
    def run(self):
        """ Initialize the runner function with passed args, kwargs """

        self.function_to_run(*self.args, **self.kwargs)
        self.signals.allfinished.emit()

marc's avatar
marc committed
86
87
class DTObservationProgram(Ui_mainWindow):    
  
88
    def __init__(self, mainWindow):
marc's avatar
marc committed
89
90
91
92
93
        logger.info('Initialization of DTObsGUI')
        #self.myDT = telescope(setmode='J2000', consoleHost='consoledemo.dmz.camras.nl')
        self.myMeas = Measurements()
        self.myMetaData = MetaData()
        
94
95
96
97
98
99
100
101
        self.radec = None
        Ui_mainWindow.__init__(self)
        self.setupUi(mainWindow)
        self.actionOpen.triggered.connect(self.openFileNameDialog)
        self.actionClose.triggered.connect(self.closeMeasurement)
        self.actionQuit.triggered.connect(self.quitDTObs)
        self.pushButtonStartMeasurement.clicked.connect(self.startMeasurement)
        self.pushButtonStopMeasurement.clicked.connect(self.stopMeasurement)
102
        self.pushButtonOutputDirectory.clicked.connect(self.selectOutputDirectory)
marc's avatar
marc committed
103
104
        self.homedir = os.environ['HOME']
        self.lineEditOutputDir.setText(self.homedir)
105
        '''
marc's avatar
marc committed
106
        Read the available tools from measurement Class and store them in the 
107
108
109
110
111
        comboBoxProgramma for selection.
        '''
        indexNR=0
        for tool in self.myMeas.getTools():
            self.comboBoxProgramma.setItemText(indexNR, tool)
marc's avatar
marc committed
112
            indexNR+=1
113
114
115
116
117
118
119

        self.threadpool = QThreadPool()

    def openFileNameDialog(self):
        '''
        Clear tableWidget and read pointings from file
        '''
120
        fileName,_ = QFileDialog.getOpenFileName(None, 'Open File', "","Meas Files (*.dat);;All Files (*)")
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
        if fileName:
            reader = csv.reader(open(fileName),delimiter='\t')
            rowPosition = self.tableWidgetPointings.rowCount()

            for meas, ra, dec in reader:
                self.radec = SkyCoord(float(ra)*u.degree, float(dec)*u.degree, frame='icrs')
                (raStr, decStr)  = self.radec.to_string('hmsdms').split()

                self.tableWidgetPointings.insertRow(rowPosition)
                self.tableWidgetPointings.setItem(rowPosition, 0, QTableWidgetItem(raStr))
                self.tableWidgetPointings.setItem(rowPosition, 1, QTableWidgetItem(decStr))
                self.tableWidgetPointings.setItem(rowPosition, 2, QTableWidgetItem(""))

                rowPosition += 1

        self.tableWidgetPointings.resizeColumnsToContents()
marc's avatar
marc committed
137
        logger.info('Imported {} pointings'.format(rowPosition))
138
139
140
141
142
143
        
    def selectOutputDirectory(self):
        '''
        Select the output directory to store the measurements
        '''
        dialog = QFileDialog()
marc's avatar
marc committed
144
        folder_path = dialog.getExistingDirectory(None, "Select Folder",self.homedir)
145
        self.lineEditOutputDir.setText(folder_path)
marc's avatar
marc committed
146
        
147
148
149
150
151
    def closeMeasurement(self):
        for rowPosition in range(self.tableWidgetPointings.rowCount(),-1,-1):
            self.tableWidgetPointings.removeRow(rowPosition)

    def quitDTObs(self):
152
        logging.shutdown()
153
154
155
156
        sys.exit(app.exec_())

    def allCompleted(self):
        """ Callback function when all pointings completed """
marc's avatar
marc committed
157
        logging.info("All pointings completed")
158
159
160
161
162
163
164
165

    def measCompleted(self, meas_num, status):
        """ Make the meas_num-th row of the table green """
        colors = {'Completed': QtGui.QColor('green'),
                  'Slewing'  : QtGui.QColor('yellow'),
                  'Measuring': QtGui.QColor('cyan')}

        self.tableWidgetPointings.item(meas_num, 2).setText(status)
marc's avatar
marc committed
166
167
168
169
170
171
        '''
        TODO
        '''
        #self.tableWidgetPointings.item(meas_num, 3).setText(measFile.name))

        for column in range(4):
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
            self.tableWidgetPointings.item(meas_num,column).setBackground(colors[status])
        self.tableWidgetPointings.resizeColumnsToContents()

    def goToSetpoints(self, setpoints, oneSetpointCompleteSignal=None, progressSignal=None):
        """ Send a list of setpoints to the telescope """
        for setpoint_nr, setpoint in enumerate(setpoints):
            self.myDT.setRaDec(setpoint)
            oneSetpointCompleteSignal.emit(setpoint_nr, 'Slewing')
            time.sleep(3)
            dist = np.sqrt(self.myDT.dist_el**2+self.myDT.dist_az**2)
            firstDist = dist
            while not dist < 0.01*u.deg:
                percentSlew = max(100 - dist/firstDist*100, 0)
                progressSignal.emit(setpoint_nr, percentSlew, "{:.3f}°".format(dist.value))
                #print("{:.3f}".format(dist))
                #print("{:2.0f}".format(percentSlew.value))
                self.myDT.getDistance(waitForUpdate=True)
                dist = np.sqrt(self.myDT.dist_el**2+self.myDT.dist_az**2)

            oneSetpointCompleteSignal.emit(setpoint_nr, 'Measuring')
            self.doMeasurement(setpoint_nr, progressSignal=progressSignal)
            oneSetpointCompleteSignal.emit(setpoint_nr, 'Completed')

    def updateProgress(self, meas_num, progress_percent, remaining_str):
        """
        Update the table with some progress indicator

        meas_num: the row which needs to be updated
        progress_percent: integer giving the percentage complete
        remaining_str: string indicating how much remaining, e.g. "1:30" or "3°"
        """
        #self.tableWidgetPointings.item(meas_num, 2).setText(remaining_str)
        self.tableWidgetPointings.item(meas_num, 2).setText(str(progress_percent)+"%")

marc's avatar
marc committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    def setMetaData(self):
        '''
        Define metadata
        '''   
        self.myMetaData.description = self.textEditDescription.toPlainText()
        self.myMetaData.startTime = time.strftime("%Y%m%d-%H%M%S")
        self.myMetaData.operator1 = self.lineEditOperator1.text()
        self.myMetaData.operator2 = self.lineEditOperator2.text()
        self.myMetaData.operator3 = self.lineEditOperator3.text()
        self.myMetaData.tool = measProgrammel 
        self.myMetaData.integrationTime = intgrationTime        
        self.myMetaData.outputDirectory = outputDir
        self.myMetaData.outputFile = outputFile
        self.myMetaData.RaDEC = self.radec
        self.myMetaData.refactionEnabled = self.checkBoxRefractionEnabled.checkStateSet()
        self.myMetaData.refactionEnabled = self.checkBoxDTModelEnabled.checkStateSet()

    def writeMetaData(self,file):
        for key, value in myData.getMetaData().items():
            file.write(str(line))
            logging.info('#key: {}\t value: {}'.format(k,v))
227
228
229
230

    def doMeasurement(self, measnum, progressSignal=None):
        """ 
        Dumping data into file including meta-data
231
        measProgramme: cli command read from comboBoxProgramma
232
        integrationTime: string read from spinBoxIntTime
233
        measurement: result of measurement of which 
234
        data: is the stdout result which need to be stored line by line
marc's avatar
marc committed
235
        measFile: result file storing the stdout results including meta data
236
237
238
        """
        integrationTime = self.spinBoxIntTime.value()
        measProgramme = self.comboBoxProgramma.currentText()
239
        outputDir = self.lineEditOutputDir.text()
marc's avatar
marc committed
240
241
242
243
244
245
        outputFile = '/DT-' + '{:03d}'.format(measnum) + '-' + time.strftime("%Y%m%d") + '.dat'
        measFile = open(outputDir + outputFile,'w')
        
        self.setMetaData(self)
        self.writeMetaData(self,measFile)
                
246
        logging.info("Output to file: {}".format(measFile))
marc's avatar
marc committed
247
248
        
        self.myMeas.startMeasurement(measProgramme, integrationTime, measFile)
249

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
        for sec in range(integrationTime):
            remainstring =  str(int((integrationTime-sec)/60)) + ":"
            remainstring += "{:02}".format((integrationTime-sec)%60)
            progressSignal.emit(measnum, int(float(sec)/integrationTime*100), remainstring)
            time.sleep(1)
        measFile.close()

    def startMeasurement(self):
        print("Measurement started")
        setpoints = []
        for meas in range(0,self.tableWidgetPointings.rowCount()):
            ra  = self.tableWidgetPointings.item(meas, 0).text()
            dec = self.tableWidgetPointings.item(meas, 1).text()

            self.tableWidgetPointings.item(meas, 2).setText("Scheduled")
            self.tableWidgetPointings.resizeColumnsToContents()
            setpoint = SkyCoord(ra, dec, frame='icrs')
            setpoints.append(setpoint)

        worker = Worker(self.goToSetpoints, setpoints)
        worker.signals.finished.connect(self.measCompleted)
        worker.signals.allfinished.connect(self.allCompleted)
        worker.signals.progress.connect(self.updateProgress)
        self.threadpool.start(worker)

    def stopMeasurement(self):
        print("Measurement stopped")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = QMainWindow()

    prog = DTObservationProgram(mainWindow)

    mainWindow.show()
    sys.exit(app.exec_())