class FiberEditor(AppWindow): def __init__(self, parent=None): super().__init__(parent) self.factory = FiberFactory() self.setWindowTitle(self.tr("Fiber Editor")) actions = { 'new': (self.tr("&New"), 'document-new', QtGui.QKeySequence.New, self.actionNew), 'open': (self.tr("&Open"), 'document-open', QtGui.QKeySequence.Open, self.actionOpen), 'save': (self.tr("&Save"), 'document-save', QtGui.QKeySequence.Save, self.save), 'saveas': (self.tr("Save &As..."), 'document-save-as', QtGui.QKeySequence.SaveAs, self.actionSaveAs), 'quit': ( self.tr("&Quit"), None, # 'application-exit', QtGui.QKeySequence.Quit, self.close), 'info': (self.tr("&Fiber properties"), 'document-properties', [QtGui.QKeySequence("Ctrl+I")], self.actionInfo), 'add': (self.tr("&Add layer"), 'list-add', [QtGui.QKeySequence("Ctrl+Shift++")], self.actionAddLayer), 'remove': (self.tr("&Remove layer"), 'list-remove', [QtGui.QKeySequence("Ctrl+-")], self.actionRemoveLayer), } menus = [(self.tr("&File"), ['new', 'open', '-', 'save', 'saveas', '-', 'quit']), (self.tr("Fibe&r"), ['info', '-', 'add', 'remove'])] toolbars = [['new', 'open', 'save', 'info'], ['add', 'remove']] self.initActions(actions) self.initMenubars(self.menuBar(), menus) self.initToolbars(toolbars) self._initLayout() self.setDirty(False) self.actionNew() def actionNew(self): if self._closeDocument(): self.factory = FiberFactory() self.factory.addLayer(name="core", radius=4e-6, index=1.454) self.factory.addLayer(name="cladding", index=1.444) self.initLayerList() self.updateInfo() def actionOpen(self, filename=None): if not self._closeDocument(): return if not filename: openDialog = QtGui.QFileDialog() openDialog.setWindowTitle(self.tr("Open fiber...")) openDialog.setDirectory(self._dir) openDialog.setAcceptMode(QtGui.QFileDialog.AcceptOpen) openDialog.setNameFilter(self.tr("Fibers (*.fiber)")) if openDialog.exec_() == QtGui.QFileDialog.Accepted: filename = openDialog.selectedFiles()[0] self._dir = openDialog.directory() if filename: with open(filename, 'r') as f: self.factory.load(f) self._dir = os.path.dirname(filename) self.initLayerList() self.setDirty(False) self.setDocumentName(filename) self.statusBar().showMessage(self.tr("Fiber opened"), 5000) self.updateInfo() def save(self): if self.documentName() == "": self.actionSaveAs() return # actionSaveAs will call save again # Use temporary file to prevent overwriting existing file in case # of error with TemporaryFile(mode="w+") as f: self.factory.dump(f) f.seek(0) with open(self.documentName(), 'w') as fd: copyfileobj(f, fd) # with open(self.documentName(), 'w') as f: # self.factory.dump(f) self.setDirty(False) self.statusBar().showMessage(self.tr("Fiber saved"), 5000) super().save() def actionSaveAs(self): saveDialog = QtGui.QFileDialog() saveDialog.setWindowTitle(self.tr("Save fibers as...")) saveDialog.setDirectory(self._dir) saveDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) saveDialog.setNameFilter(self.tr("Fibers (*.fiber)")) saveDialog.setDefaultSuffix('fiber') if saveDialog.exec_() == QtGui.QFileDialog.Accepted: self.setDocumentName(saveDialog.selectedFiles()[0]) self.save() self._dir = saveDialog.directory() def actionInfo(self): FiberPropertiesWindow(self.factory._fibers, self).exec_() def actionAddLayer(self): self.addLayer() def actionRemoveLayer(self): self.removeLayer() def setDirty(self, df): super().setDirty(df) self.actions['save'].setEnabled(df) self.fnumInput.setRange(1, len(self.factory)) self.fnumSlider.setRange(1, self.fnumInput.maximum()) self.updateInfo() def _initLayout(self): self.layerName = QtGui.QLineEdit() self.layerName.textChanged.connect(self.changeLayerName) self.layerName.setEnabled(False) self.layerList = QtGui.QListWidget() self.layerList.itemSelectionChanged.connect(self.selectLayer) self.layerList.itemActivated.connect(self.actLayerName) self.initLayerList() layout1 = QtGui.QVBoxLayout() layout1.addWidget(QtGui.QLabel(self.tr("Fiber layers:"))) layout1.addWidget(self.layerList) frame1 = QtGui.QFrame() frame1.setLayout(layout1) lnFormLayout = QtGui.QFormLayout() lnFormLayout.addRow(QtGui.QLabel(self.tr("Layer name:")), self.layerName) l2splitter = QtGui.QSplitter(QtCore.Qt.Vertical) l2splitter.addWidget(self._initGeomFrame()) l2splitter.addWidget(self._initMatFrame()) layout2 = QtGui.QVBoxLayout() layout2.addLayout(lnFormLayout) layout2.addWidget(l2splitter) frame2 = QtGui.QFrame() frame2.setLayout(layout2) self.wlInput = QtGui.QDoubleSpinBox() self.wlInput.setSuffix(" nm") self.wlInput.setRange(500, 3000) self.wlInput.setSingleStep(1) self.wlInput.setValue(1550) self.wlInput.valueChanged.connect(self.wlChanged) self.fnumInput = QtGui.QSpinBox() self.fnumInput.setValue(1) self.fnumInput.setMinimum(1) self.fnumInput.setMaximum(len(self.factory)) self.fnumInput.valueChanged.connect(self.fnumChanged) wlForm = QtGui.QFormLayout() wlForm.addRow(QtGui.QLabel(self.tr("Wavelength:")), self.wlInput) wlForm.addRow(QtGui.QLabel(self.tr("Fiber #")), self.fnumInput) self.fnumSlider = QtGui.QSlider(QtCore.Qt.Horizontal) self.fnumSlider.setValue(self.fnumInput.value()) self.fnumSlider.setMinimum(1) self.fnumSlider.setMaximum(self.fnumInput.maximum()) self.fnumSlider.valueChanged.connect(self.fnumChanged) self.infoTable = FiberInfoTable() self.fiberPlot = FiberPlot() infoTab = QtGui.QTabWidget() infoTab.addTab(self.infoTable, self.tr("Info")) infoTab.addTab(self.fiberPlot, self.tr("Graph")) layout3 = QtGui.QVBoxLayout() layout3.addLayout(wlForm) layout3.addWidget(self.fnumSlider) layout3.addWidget(infoTab) frame3 = QtGui.QFrame() frame3.setLayout(layout3) splitter = QtGui.QSplitter(self) splitter.addWidget(frame1) splitter.addWidget(frame2) splitter.addWidget(frame3) self.setCentralWidget(splitter) def _initGeomFrame(self): self.geomType = QtGui.QComboBox() self.geomType.addItems(geometry.__all__) self.geomType.setEnabled(False) self.geomType.setCurrentIndex(-1) self.geomType.currentIndexChanged.connect(self.selectGeomType) self.geomLayout = QtGui.QFormLayout() self.geomLayout.addRow(QtGui.QLabel(self.tr("Geometry type:")), self.geomType) geomFrame = QtGui.QGroupBox(self.tr("Geometry")) geomFrame.setLayout(self.geomLayout) return geomFrame def _initMatFrame(self): self.matType = QtGui.QComboBox() self.matType.addItems(material.__all__) self.matType.setEnabled(False) self.matType.setCurrentIndex(-1) self.matType.currentIndexChanged.connect(self.selectMatType) self.matPropBut = QtGui.QPushButton(self.getIcon('info'), "") self.matPropBut.clicked.connect(self.aboutFiberMaterial) self.matPropBut.setEnabled(False) layout = QtGui.QHBoxLayout() layout.addWidget(self.matType) layout.addWidget(self.matPropBut) self.matLayout = QtGui.QFormLayout() self.matLayout.addRow(QtGui.QLabel(self.tr("Material type:")), layout) matFrame = QtGui.QGroupBox(self.tr("Material")) matFrame.setLayout(self.matLayout) return matFrame def initLayerList(self): self.layerList.clear() for i, layer in enumerate(self.factory.layers, 1): if layer.name == "": name = "layer {}".format(i) else: name = layer.name self.layerList.addItem(name) self.actions['remove'].setEnabled(False) self.layerName.setText("") def selectLayer(self): index = self.layerList.currentRow() self.layerName.setEnabled(True) with blockSignals(self.layerName): self.layerName.setText(self.factory.layers[index].name) self.initGeom() self.initMat() if index == len(self.factory.layers) - 1: self.actions['remove'].setEnabled(False) else: self.actions['remove'].setEnabled(True) def addLayer(self): index = self.layerList.currentRow() self.factory.addLayer(index + 1) self.layerList.insertItem(index + 1, "layer {}".format(index + 2)) self._adjustLayerNames() self.layerList.setCurrentRow(index + 1) self.setDirty(True) def removeLayer(self): index = self.layerList.currentRow() self.layerList.takeItem(index) self.factory.removeLayer(index) self._adjustLayerNames() self.layerList.setCurrentRow(index) self.setDirty(True) def _adjustLayerNames(self): for i, layer in enumerate(self.factory.layers): if layer.name == "": name = "layer {}".format(i + 1) if self.layerList.item(i): self.layerList.item(i).setText(name) def changeLayerName(self, newText): index = self.layerList.currentRow() self.factory.layers[index].name = newText if newText == "": name = "layer {}".format(index + 1) else: name = newText if self.layerList.currentItem(): self.layerList.currentItem().setText(name) self.setDirty(True) def actLayerName(self, item): self.layerName.setFocus() def _updateParam(self, pname, pindex, value): layerIndex = self.layerList.currentRow() layer = self.factory.layers[layerIndex] layer[pname][pindex] = value self.setDirty(True) def initGeom(self): layerIndex = self.layerList.currentRow() if layerIndex == len(self.factory.layers) - 1: self.geomType.setEnabled(False) else: self.geomType.setEnabled(True) geomtype = self.factory.layers[layerIndex].type gtidx = self.geomType.findText(geomtype) # We call selectGeomType directly instead of emitting the signal, # to prevent it setting dirty state, since we only display the # current state, we are not changing the geometry type with blockSignals(self.geomType): self.geomType.setCurrentIndex(gtidx) self.selectGeomType(gtidx, False) def selectGeomType(self, index, change=True): util.clearLayout(self.geomLayout, 2) layerIndex = self.layerList.currentRow() self.factory.layers[layerIndex].type = self.geomType.currentText() if index == 0: self.setStepIndexGeom() elif index == 1: self.setSuperGaussianGeom() if change: self.setDirty(True) def setStepIndexGeom(self): layerIndex = self.layerList.currentRow() if layerIndex == len(self.factory.layers) - 1: return layer = self.factory.layers[layerIndex] self.radiusInput = SLRCWidget() self.radiusInput.setSuffix(" µm") self.radiusInput.setScaleFactor(1e6) self.radiusInput.codeParams = ['r', 'fp', 'mp'] self.radiusInput.setValue(layer.radius) self.radiusInput.valueChanged.connect(self.updateRadius) self.geomLayout.addRow(QtGui.QLabel(self.tr("Radius:")), self.radiusInput) def setSuperGaussianGeom(self): layerIndex = self.layerList.currentRow() layer = self.factory.layers[layerIndex] self.setStepIndexGeom() self.muInput = SLRCWidget() self.muInput.setSuffix(" µm") self.muInput.setScaleFactor(1e6) self.muInput.setRange(-100, 100) self.muInput.codeParams = ['r', 'fp', 'mp'] self.muInput.setValue(layer.tparams[1]) self.muInput.valueChanged.connect( lambda v: self._updateParam("tparams", 1, v)) self.cInput = SLRCWidget() self.cInput.setRange(0.001, 100) self.cInput.codeParams = ['r', 'fp', 'mp'] self.cInput.setScaleFactor(1e6) self.cInput.setValue(layer.tparams[2]) self.cInput.valueChanged.connect( lambda v: self._updateParam("tparams", 2, v)) self.mInput = SLRCWidget() self.mInput.setRange(1, 100) self.mInput.codeParams = ['r', 'fp', 'mp'] self.mInput.setValue(layer.tparams[3]) self.mInput.valueChanged.connect( lambda v: self._updateParam("tparams", 3, v)) self.geomLayout.addRow(QtGui.QLabel(self.tr("Center (mu):")), self.muInput) self.geomLayout.addRow(QtGui.QLabel(self.tr("Width (c):")), self.cInput) self.geomLayout.addRow(QtGui.QLabel(self.tr("m parameter:")), self.mInput) def updateRadius(self, value): self._updateParam("tparams", 0, value) def initMat(self): self.matType.setEnabled(True) self.matPropBut.setEnabled(True) layerIndex = self.layerList.currentRow() mattype = self.factory.layers[layerIndex].material mtidx = self.matType.findText(mattype) state = self.matType.blockSignals(True) self.matType.setCurrentIndex(mtidx) self.selectMatType(mtidx, False) self.matType.blockSignals(state) def selectMatType(self, index, change=True): layerIndex = self.layerList.currentRow() layer = self.factory.layers[layerIndex] layer.material = self.matType.currentText() util.clearLayout(self.matLayout, 2) mat = material.__dict__[layer.material] if mat.nparams == 0: pass # No parameters to display elif issubclass(mat, material.Fixed): if change: layer.mparams = [1.444] self.setFixedMaterial(layer) elif issubclass(mat, material.compmaterial.CompMaterial): if change: layer.mparams = [0.05] self.setConcentrationMaterial(layer) if change: self.setDirty(True) def setFixedMaterial(self, layer): self.indexInput = SLRCWidget() self.indexInput.setRange(1, 2) self.indexInput.setSingleStep(0.01) self.indexInput.setValue(layer.mparams[0]) self.indexInput.valueChanged.connect(self.updateIndex) self.indexInput.codeParams = ['r', 'fp', 'mp'] self.matLayout.addRow(QtGui.QLabel(self.tr("Index:")), self.indexInput) def updateIndex(self, value): self._updateParam("mparams", 0, value) def setConcentrationMaterial(self, layer): layerIndex = self.layerList.currentRow() layer = self.factory.layers[layerIndex] self.molInput = SLRCWidget() self.molInput.setSuffix(" %") self.molInput.setScaleFactor(100) self.molInput.setValue(layer.mparams[0]) self.molInput.valueChanged.connect(self.updateMol) self.molInput.codeParams = ['r', 'fp', 'mp'] self.matLayout.addRow(QtGui.QLabel(self.tr("Molar concentration:")), self.molInput) def updateMol(self, value): self._updateParam("mparams", 0, value) def updateInfo(self): if self.factory.layers: self.infoTable.updateInfo(self.factory[self.fnumInput.value() - 1], self.wlInput.value() * 1e-9) self.fiberPlot.updateInfo(self.factory[self.fnumInput.value() - 1], self.wlInput.value() * 1e-9) def fnumChanged(self, value): if self.fnumInput.value() != value: self.fnumInput.setValue(value) if self.fnumSlider.value() != value: self.fnumSlider.setValue(value) self.updateInfo() def wlChanged(self, value): self.updateInfo() def aboutFiberMaterial(self): layerIndex = self.layerList.currentRow() layer = self.factory.layers[layerIndex] mat = material.__dict__[layer.material] msgBox = QtGui.QMessageBox() msgBox.setWindowTitle(mat.name) text = "<h1>{}</h1>".format(mat.name) if mat.info: text += "<p>{}</p>".format(mat.info) if mat.url: text += '<p><a href="{url}">{url}</a></p>'.format(url=mat.url) msgBox.setText(text) msgBox.exec_()
class ModeSolver(AppWindow): PARAMETERS = (("cutoff (V)", "cutoff (wavelength)"), ("neff", "b", "vp", "beta0"), ("ng", "vg", "beta1"), ("D", "beta2"), ("S", "beta3")) def __init__(self, parent=None): super().__init__(parent) self.doc = SolverDocument(self) self.setWindowTitle(self.tr("Mode Solver")) self._initLayout() actions = { 'open': ( self.tr("&Open"), 'document-open', QtGui.QKeySequence.Open, self.actionOpen ), 'save': ( self.tr("&Save"), 'document-save', QtGui.QKeySequence.Save, self.save), 'exportcur': ( self.tr("&Export current table"), 'export', [QtGui.QKeySequence("Ctrl+E")], self.export_current_table ), 'quit': ( self.tr("&Quit"), None, # 'application-exit', QtGui.QKeySequence.Quit, self.close ), 'new': ( self.tr("&New fiber file"), 'document-new', QtGui.QKeySequence.New, self.fiberSelector.editFiber ), 'load': ( self.tr("&Load fiber file"), 'document-open', QtGui.QKeySequence.Open, self.fiberSelector.chooseFiber ), 'edit': ( self.tr("&Edit fiber"), 'pen', [], self.fiberSelector.editFiber ), 'info': ( self.tr("&Fiber properties"), 'document-properties', [QtGui.QKeySequence("Ctrl+I")], self.fiberSelector.fiberProperties ), 'start': ( self.tr("&Run simulation"), 'media-playback-start', [QtGui.QKeySequence("F5")], self.run_simulation ), 'stop': ( self.tr("&Stop simulation"), 'media-playback-stop', [QtGui.QKeySequence("Ctrl+.")], self.stop_simulation ), 'mcalc': ( self.tr("&Material calculator"), 'index-calculator', [QtGui.QKeySequence("F8")], self.toggle_mcalc ), 'wlcalc': ( self.tr("&Wavelength calculator"), 'lambda-calculator', [QtGui.QKeySequence("F7")], self.toggle_wlcalc ), 'plotchareq': ( self.tr("&Plot characteristic equation"), None, [], self.plot_chareq ), 'clearcaches': ( self.tr("&Clear all caches"), None, [], self.doc.clear_all_caches ), 'simparams': ( self.tr("Advanced &Parameters"), 'document-properties', [], self.simParams ), 'paramwin': ( self.tr("&Parameters"), 'function', [QtGui.QKeySequence("F2")], self.togglePanes ), 'tablewin': ( self.tr("&Result table"), 'table', [QtGui.QKeySequence("F3")], self.togglePanes ), 'graphwin': ( self.tr("&Graph"), 'statistics', [QtGui.QKeySequence("F4")], self.togglePanes ), 'fullscreen': ( self.tr("&Fullscreen"), 'view-fullscreen', [QtGui.QKeySequence("F11")], self.toggleFullscreen ), 'fields': ( self.tr("Show &fields"), 'report', [QtGui.QKeySequence("F6")], self.plotFields ) } menus = [ ( self.tr("&File"), [ 'open', 'save', 'exportcur', '-', 'quit' ] ), ( self.tr("Fibe&r"), [ 'new', 'load', '-', 'edit', 'info', ] ), ( self.tr("&Simulation"), [ 'start', 'stop', '-', 'simparams', ] ), ( self.tr("&Tools"), [ 'fields', '-', 'wlcalc', 'mcalc' ] ), ( self.tr("&Debug"), [ 'plotchareq', self.logmenu, 'clearcaches', ] ), ( self.tr("&Window"), [ 'paramwin', 'tablewin', 'graphwin', '-', 'fullscreen', ] ), ] toolbars = [ ['open', 'save', 'exportcur'], ['start', 'stop'], ['fields', '-', 'wlcalc', 'mcalc'], ['paramwin', 'tablewin', 'graphwin'], ] self.initActions(actions) self.initMenubars(self.menuBar(), menus) self.initToolbars(toolbars) self.actions['exportcur'].setEnabled(False) self.actions['edit'].setEnabled(False) self.actions['info'].setEnabled(False) self.actions['start'].setCheckable(True) self.actions['stop'].setCheckable(True) self.actions['stop'].setChecked(True) self.actions['stop'].setEnabled(False) self.actions['mcalc'].setCheckable(True) self.actions['wlcalc'].setCheckable(True) self.actions['paramwin'].setCheckable(True) self.actions['paramwin'].setChecked(True) self.actions['tablewin'].setCheckable(True) self.actions['tablewin'].setChecked(True) self.actions['graphwin'].setCheckable(True) self.actions['graphwin'].setChecked(True) self.actions['fullscreen'].setCheckable(True) self.actions['plotchareq'].setEnabled(False) self.actions['fields'].setEnabled(False) self.wavelengthInput.setValue(1550e-9) self.setDirty(False) self.closed.connect(self.doc.stop_thread) self.mcalc = None self.wlcalc = None def _initLayout(self): self.progressBar = QtGui.QProgressBar() self.statusBar().addWidget(self.progressBar, 1) self.timeLabel = QtGui.QLabel() self.timeLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) self.statusBar().addPermanentWidget(self.timeLabel) self.time = QtCore.QTime() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.updateTime) self.countLabel = QtGui.QLabel(self.tr("No fiber")) self.countLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) self.statusBar().addPermanentWidget(self.countLabel) self.splitter = QtGui.QSplitter(self) self.splitter.addWidget(self._parametersFrame()) self.splitter.addWidget(self._modesFrame()) self.plotFrame = PlotFrame(self) self.plotFrame.modified.connect(self.setDirty) self.modeTableView.selChanged.connect(self.plotFrame.updateModeSel) self.modeTableModel.dataChanged.connect(self.plotFrame.updatePlot) self.splitter.addWidget(self.plotFrame) self.setCentralWidget(self.splitter) self.doc.computeStarted.connect(self.initProgressBar) self.doc.valueAvailable.connect(self.updateProgressBar) self.doc.computeFinished.connect(self.stopProgressBar) def _parametersFrame(self): self.fiberSelector = FiberSelector(self.doc, self) self.fiberSelector.fileLoaded.connect(self.updateFiber) self.fiberSelector.fiberEdited.connect(self.updateFiber) self.wavelengthInput = SLRCWidget() self.wavelengthInput.setSuffix(" nm") self.wavelengthInput.setScaleFactor(1e9) self.wavelengthInput.setRange(200, 10000) self.wavelengthInput.setSingleStep(1) self.wavelengthInput.valueChanged.connect(self.updateWavelengths) self.modeSelector = QtGui.QComboBox() self.modeSelector.addItems(['vector', 'scalar', 'both']) self.modeSelector.currentIndexChanged.connect(self.setMode) formLayout = QtGui.QFormLayout() formLayout.addRow( QtGui.QLabel(self.tr("Wavelength")), self.wavelengthInput) formLayout.addRow( QtGui.QLabel(self.tr("Modes")), self.modeSelector) self.nuMaxInput = QtGui.QSpinBox() self.nuMaxInput.valueChanged.connect(self.setMaxNu) self.nuMaxInput.setRange(-1, 99) self.nuMaxInput.setSpecialValueText(" ") self.mMaxInput = QtGui.QSpinBox() self.mMaxInput.setRange(0, 100) self.mMaxInput.valueChanged.connect(self.setMaxM) self.mMaxInput.setSpecialValueText(" ") simParamFormLayout = QtGui.QHBoxLayout() simParamFormLayout.addWidget( QtGui.QLabel(self.tr("l max")), 0, QtCore.Qt.AlignRight) simParamFormLayout.addWidget(self.nuMaxInput) simParamFormLayout.addWidget( QtGui.QLabel(self.tr("m max")), 0, QtCore.Qt.AlignRight) simParamFormLayout.addWidget(self.mMaxInput) simParamLayout = QtGui.QVBoxLayout() simParamLayout.addLayout(simParamFormLayout) self.simParamBoxes = {} for row in self.PARAMETERS: hlayout = QtGui.QHBoxLayout() for param in row: box = QtGui.QCheckBox(param) box.toggled.connect(self.updateParams) hlayout.addWidget(box) self.simParamBoxes[param] = box hlayout.addStretch(1) simParamLayout.addLayout(hlayout) simParamsGroup = QtGui.QGroupBox(self.tr("Simulation Parameters")) simParamsGroup.setLayout(simParamLayout) topLayout = QtGui.QVBoxLayout() topLayout.addWidget(QtGui.QLabel(self.tr("Fiber"))) topLayout.addWidget(self.fiberSelector) topLayout.addLayout(formLayout) topLayout.addWidget(simParamsGroup) topLayout.addStretch(1) topFrame = QtGui.QFrame() topFrame.setLayout(topLayout) splitter = QtGui.QSplitter(self) splitter.addWidget(topFrame) return splitter def _modesFrame(self): self.modeTableModel = ModeTableModel(self.doc, self) self.modeTableProxy = QtGui.QSortFilterProxyModel(self) self.modeTableProxy.setSourceModel(self.modeTableModel) self.modeTableProxy.setSortRole(QtCore.Qt.UserRole) self.modeTableProxy.setDynamicSortFilter(True) self.modeTableView = ModeTableView(self.modeTableProxy) self.modeTableView.selChanged.connect(self.updateUIsel) self.modeTableModel.dataChanged.connect( self.modeTableView.resizeColumnsToContents) self.modeTableModel.modelReset.connect(self.updateUImodes) self.fiberSlider = FiberSlider() self.fiberSlider.valueChanged.connect(self.setFiber) self.wavelengthSlider = WavelengthSlider() self.wavelengthSlider.valueChanged.connect(self.setWavelength) self.showhidesel = ShowHideMode() self.showhidesel.showModes.connect(self.on_show_modes) self.showhidesel.hideModes.connect(self.on_hide_modes) layout1 = QtGui.QHBoxLayout() layout1.addWidget(self.fiberSlider) layout1.addWidget(self.wavelengthSlider) layout2 = QtGui.QVBoxLayout() layout2.addLayout(layout1) layout2.addWidget(self.showhidesel) layout2.addWidget(self.modeTableView, stretch=1) frame = QtGui.QFrame() frame.setLayout(layout2) # Default values self.nuMaxInput.setValue(-1) self.mMaxInput.setValue(0) return frame def documentName(self): if self.doc.factory: fn = self.doc.filename p, f = os.path.split(fn) b, e = os.path.splitext(f) return os.path.join(p, b+".solver") return "" def actionOpen(self, filename=None): if not self._closeDocument(): return if not filename: openDialog = QtGui.QFileDialog() openDialog.setWindowTitle(self.tr("Open solver...")) openDialog.setDirectory(self._dir) openDialog.setAcceptMode(QtGui.QFileDialog.AcceptOpen) openDialog.setNameFilter(self.tr("Solver (*.solver)")) if openDialog.exec_() == QtGui.QFileDialog.Accepted: filename = openDialog.selectedFiles()[0] self._dir = openDialog.directory() if filename: if self.load(filename): self._dir = os.path.dirname(filename) self.setDirty(False) self.statusBar().showMessage(self.tr("Solver loaded"), 5000) def load(self, filename): # Test for fiber file p, f = os.path.split(filename) b, e = os.path.splitext(f) fiberfile = os.path.join(p, b+".fiber") if os.path.exists(fiberfile): self.doc.filename = fiberfile self.fiberSelector.fileLoaded.emit() else: # Trouver fiberfile... print(fiberfile, "not found") return False self.stop_simulation() with open(filename, 'r') as f: s = json.load(f) self.wavelengthInput.setValue(s['wl']) self.modeSelector.setCurrentIndex(int(s['modes'])) self.doc.params = s['params'] for p, box in self.simParamBoxes.items(): with blockSignals(box): box.setChecked(p in self.doc.params) self.nuMaxInput.setValue(int(s['numax'])) self.mMaxInput.setValue(int(s['mmax'])) self.fiberSlider.fiberInput.setValue(int(s['fnum'])) self.wavelengthSlider.wavelengthInput.setValue(int(s['wlnum'])) self.actions['paramwin'].setChecked(s['panes']['params']) self.actions['tablewin'].setChecked(s['panes']['modes']) self.actions['graphwin'].setChecked(s['panes']['graph']) self.togglePanes() self.plotFrame.load(s['graph']) return True def save(self): s = { 'wl': self.wavelengthInput._value, 'modes': self.modeSelector.currentIndex(), 'params': self.doc.params, 'numax': self.doc.numax if self.doc.numax is not None else -1, 'mmax': self.doc.mmax if self.doc.mmax is not None else -1, 'fnum': self.fiberSlider.fiberInput.value(), 'wlnum': self.wavelengthSlider.wavelengthInput.value(), 'panes': { 'params': int(self.actions['paramwin'].isChecked()), 'modes': int(self.actions['tablewin'].isChecked()), 'graph': int(self.actions['graphwin'].isChecked())}, 'graph': self.plotFrame.save() } # Use temporary file to prevent overwriting existing file in case # of error with TemporaryFile(mode="w+") as f: json.dump(s, f) f.seek(0) with open(self.documentName(), 'w') as fd: copyfileobj(f, fd) self.setDirty(False) self.statusBar().showMessage(self.tr("Fiber saved"), 5000) super().save() def setDirty(self, df=True): if 'save' in self.actions: if not self.doc.factory: self.actions['save'].setEnabled(False) else: self.actions['save'].setEnabled(df) if not self.doc.factory: df = False super().setDirty(df) def _updateFiberCount(self): if self.doc.factory: nf = len(self.doc.fibers) nw = len(self.doc.wavelengths) self.countLabel.setText( self.tr("{} F x {} W = {}").format( nf, nw, nf*nw)) self.countLabel.setToolTip( self.tr("{} fibers x {} wavelengths = {} combinations".format( nf, nw, nf*nw))) def updateFiber(self): """New fiber loaded, or fiber modified.""" self.actions['new'].setEnabled(False) self.actions['edit'].setEnabled(True) self.actions['info'].setEnabled(True) self.actions['plotchareq'].setEnabled(True) self.fiberSelector.updateFiberName() self.fiberSlider.setNum(len(self.doc.fibers)) self.setDirty(True) self._updateFiberCount() self.statusBar().showMessage(self.tr("Fiber factory loaded"), 5000) def updateWavelengths(self): self.doc.wavelengths = self.wavelengthInput self.wavelengthSlider.setNum(len(self.doc.wavelengths)) self.setWavelength(self.wavelengthSlider.value()) self._updateFiberCount() self.setDirty(True) def setMode(self, index): self.doc.modeKind = self.modeSelector.currentText() self.setDirty(True) def setMaxNu(self, value): self.doc.numax = value self.setDirty(True) def setMaxM(self, value): self.doc.mmax = value self.setDirty(True) def setFiber(self, value): self.modeTableModel.setFiber(value) self.plotFrame.setFiber(value) self.showVNumber() self.setDirty(True) def setWavelength(self, value): if 0 <= value - 1 < len(self.doc.wavelengths): wl = self.doc.wavelengths[value-1] self.wavelengthSlider.wlLabel.setText( "{:.5f} nm".format(wl * 1e9)) self.modeTableModel.setWavelength(value) self.plotFrame.setWavelength(value) self.showVNumber() self.setDirty(True) def showVNumber(self): try: wlnum = self.modeTableModel._wl fnum = self.modeTableModel._fnum wl = self.doc.wavelengths[wlnum] fiber = self.doc.fibers[fnum] self.wavelengthSlider.vLabel.setText( "| V = {:.5f}".format(fiber.V0(wl))) except ValueError: pass def updateParams(self, checked): params = [] for row in self.PARAMETERS: for p in row: if self.simParamBoxes[p].isChecked(): params.append(p) self.doc.params = params self.plotFrame.updatePMButs() self.setDirty(True) def initProgressBar(self): self.progressBar.setFormat("%v / %m (%p%)") self.progressBar.setRange(0, 0) self.progressBar.setValue(0) self.time.start() self.estimation = 0 self.timer.start(0) self.actions['exportcur'].setEnabled(False) def updateProgressBar(self): tot = self.progressBar.maximum() if tot == 0: tot = self.doc.toCompute + 1 self.progressBar.setMaximum(tot) self.progressBar.setValue(self.progressBar.value() + 1) elapsed = self.time.elapsed() self.estimation = elapsed if self.doc.toCompute > 0: done = self.progressBar.value() if done: self.estimation = tot * (elapsed / done) def stopProgressBar(self): tot = self.progressBar.maximum() self.progressBar.setValue(tot) self.timer.stop() self.updateTime() self.plotFrame.updatePlot() self.actions['exportcur'].setEnabled(True) def updateTime(self): elapsed = self.time.elapsed() remaining = int(self.estimation - elapsed) if remaining > 0: self.timeLabel.setText(self.tr("E: {} (R: {})").format( msToStr(elapsed), msToStr(remaining, False))) else: self.timeLabel.setText(self.tr("E: {}").format( msToStr(elapsed))) def run_simulation(self): self.doc.ready = True self.doc.start() self.actions['start'].setEnabled(False) self.actions['stop'].setEnabled(True) self.actions['stop'].setChecked(False) def stop_simulation(self): self.timer.stop() self.progressBar.setFormat("") self.progressBar.setValue(0) self.doc.stop_thread() self.doc.ready = False self.actions['stop'].setEnabled(False) self.actions['start'].setEnabled(True) self.actions['start'].setChecked(False) def toggle_mcalc(self): if self.mcalc is None: self.mcalc = MaterialCalculator(self) self.mcalc.hidden.connect(self.actions['mcalc'].toggle) if self.actions['mcalc'].isChecked(): self.mcalc.show() else: with blockSignals(self.mcalc): self.mcalc.hide() def toggle_wlcalc(self): if self.wlcalc is None: self.wlcalc = WavelengthCalculator(self) self.wlcalc.hidden.connect(self.actions['wlcalc'].toggle) if self.actions['wlcalc'].isChecked(): self.wlcalc.show() else: with blockSignals(self.wlcalc): self.wlcalc.hide() def plot_chareq(self): sel = self.modeTableView.selectedIndexes() try: idx = self.modeTableProxy.mapToSource(sel[0]) mode = self.modeTableModel.modes[idx.row()] except IndexError: mode = None dlg = CharEqDialog(mode, self) dlg.show() def simParams(self): dlg = SimParamsDialog(self.doc) dlg.exec_() self.doc.numProcs = dlg.numProcs.value() self.doc.simulator.delta = float(dlg.delta.text()) def on_show_modes(self, what, option): self._show_hide_modes(True, what, option) def on_hide_modes(self, what, option): self._show_hide_modes(False, what, option) def _show_hide_modes(self, show, what, option): nm = self.modeTableModel.rowCount() for i in range(nm): mode = self.modeTableModel.headerData(i, QtCore.Qt.Vertical, QtCore.Qt.UserRole) if (what == 0 or (what == 1 and mode.family is ModeFamily(option+1)) or (what == 2 and mode.nu == option) or (what == 3 and mode.m == option+1)): index = self.modeTableModel.index(i, 0) self.modeTableModel.setData( index, QtCore.Qt.Checked if show else QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole) def togglePanes(self): states = [ self.actions['paramwin'].isChecked(), self.actions['tablewin'].isChecked(), self.actions['graphwin'].isChecked()] self.splitter.setSizes(states) if sum(states) == 1: self.actions['paramwin'].setEnabled(not states[0]) self.actions['tablewin'].setEnabled(not states[1]) self.actions['graphwin'].setEnabled(not states[2]) else: self.actions['paramwin'].setEnabled(True) self.actions['tablewin'].setEnabled(True) self.actions['graphwin'].setEnabled(True) self.setDirty(True) def toggleFullscreen(self): if self.isFullScreen(): self.showNormal() else: self.showFullScreen() def export_current_table(self): wlnum = self.modeTableModel._wl fnum = self.modeTableModel._fnum exportDialog = QtGui.QFileDialog() exportDialog.setWindowTitle(self.tr("Export results")) exportDialog.setDirectory(self._dir) exportDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) exportDialog.setNameFilter(self.tr("Comma Separated Values (*.csv)")) exportDialog.setDefaultSuffix('csv') if exportDialog.exec_() == QtGui.QFileDialog.Accepted: filename = exportDialog.selectedFiles()[0] self._dir = exportDialog.directory() self.doc.export(filename, wlnum, fnum) def updateUIsel(self, modes): pass # ms = len(modes) > 0 # self.actions['plotchareq'].setEnabled(ms) def updateUImodes(self): nm = self.modeTableModel.rowCount() self.actions['fields'].setEnabled(nm > 0) self.showhidesel.modes = self.modeTableModel.modes def plotFields(self): fv = FieldVisualizer(self) sm = self.modeTableView.selectedModes() if sm: fv.setModes([[m, 0, 0, 1] for m in sm]) fv.show()