|
@@ -0,0 +1,198 @@
|
|
|
+<template>
|
|
|
+ <div class="row items-baseline">
|
|
|
+ <div class="col-xs-12 col-sm-auto text-weight-bold text-center q-px-md q-py-sm">
|
|
|
+ <q-tooltip
|
|
|
+ v-if=" $store.state.guiRuntime.safeFromWL > $store.state.simulationSetup.gui.nearFieldSetup.atWL ||
|
|
|
+ $store.state.guiRuntime.safeToWL < $store.state.simulationSetup.gui.nearFieldSetup.atWL "
|
|
|
+ anchor="top middle" self="center middle"
|
|
|
+ class="bg-amber-4 text-black shadow-4">
|
|
|
+ Will use materials<br> spectrum range.
|
|
|
+ </q-tooltip>
|
|
|
+ <q-btn :loading="isRunning"
|
|
|
+ :disable="isRunning||!isNmieLoaded"
|
|
|
+ color="primary"
|
|
|
+ no-caps
|
|
|
+ :label="isNmieLoaded ? 'Run simulation' : 'Loading...'"
|
|
|
+ @click="runNearFieldSimulation">
|
|
|
+ <template #loading>
|
|
|
+ <q-spinner-gears />
|
|
|
+ </template>
|
|
|
+ </q-btn>
|
|
|
+ </div>
|
|
|
+ <div class="col-xs-grow col-sm q-px-xs">
|
|
|
+ <div class="row justify-xs-center justify-sm-start items-baseline">
|
|
|
+
|
|
|
+ <div class="col-auto">
|
|
|
+ <q-btn
|
|
|
+ color="primary"
|
|
|
+ no-caps
|
|
|
+ @click="saveSpectrumSimulation"
|
|
|
+ >Save</q-btn>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+import {
|
|
|
+ defineComponent,
|
|
|
+ computed,
|
|
|
+ // watch,
|
|
|
+ onActivated,
|
|
|
+ nextTick
|
|
|
+} from 'vue'
|
|
|
+import { useStore } from 'src/store'
|
|
|
+import { getModeName, range, rangeInt} from 'components/utils'
|
|
|
+import { cloneDeep } from 'lodash'
|
|
|
+import { saveAs } from 'file-saver'
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'RunSimulationNearField',
|
|
|
+
|
|
|
+ setup() {
|
|
|
+ const $store = useStore()
|
|
|
+
|
|
|
+ const isRunning = computed({
|
|
|
+ get: ()=> $store.state.simulationSetup.nmies.nearField.isNmieRunning,
|
|
|
+ set: val => {
|
|
|
+ val ? $store.commit('simulationSetup/markNmieNearFieldAsStarted') : $store.commit('simulationSetup/markNmieNearFieldAsFinished')
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const isNmieLoaded = computed(()=>{ return $store.state.simulationSetup.nmies.nearField.instance })
|
|
|
+
|
|
|
+ const atWL = computed(
|
|
|
+ () => $store.state.simulationSetup.current.nearFieldSetup.atWL)
|
|
|
+ //-------------------------------------------------------------------------//
|
|
|
+ //--------------------- Main --------------------------------------------//
|
|
|
+ //-------------------------------------------------------------------------//
|
|
|
+ function runNearFieldSimulation() {
|
|
|
+ if (isRunning.value) {
|
|
|
+ console.log('Some Nmie is already running!')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ isRunning.value = true
|
|
|
+ void nextTick(()=> {
|
|
|
+ $store.commit('simulationSetup/copySetupFromGuiToCurrent')
|
|
|
+
|
|
|
+ const host = $store.state.simulationSetup.current.hostIndex
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (!$store.state.simulationSetup.nmies.nearField.instance) throw 'ERROR! Scattnlay module was not loaded'
|
|
|
+ const nmie = $store.state.simulationSetup.nmies.nearField.instance
|
|
|
+ const layers = cloneDeep($store.state.simulationSetup.current.layers)
|
|
|
+ const nmieStartedTime = performance.now()
|
|
|
+
|
|
|
+ nmie.SetWavelength(atWL.value)
|
|
|
+ nmie.ClearTarget()
|
|
|
+ for (const layer of layers) {
|
|
|
+ if (layer.material.nSpline) layer.n = layer.material.nSpline.at(atWL.value)
|
|
|
+ if (layer.material.kSpline) layer.k = layer.material.kSpline.at(atWL.value)
|
|
|
+ nmie.AddTargetLayerReIm(layer.layerWidth * host, layer.n / host, layer.k / host)
|
|
|
+ }
|
|
|
+
|
|
|
+ nmie.SetModeNmaxAndType(-1, -1)
|
|
|
+
|
|
|
+ nmie.RunFieldCalculationCartesian(
|
|
|
+ $store.state.simulationSetup.current.nearFieldSetup.plotSideResolution,
|
|
|
+ $store.state.simulationSetup.current.nearFieldSetup.relativePlotSize,
|
|
|
+ $store.state.simulationSetup.current.nearFieldSetup.crossSection,
|
|
|
+ 0, 0, 0, 0
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ const nmieTotalRunTime = (performance.now()-nmieStartedTime)/1000
|
|
|
+ // console.log('Total simulation time:', nmieTotalRunTime, 's')
|
|
|
+ $store.commit('simulationSetup/setNmieNearFieldTotalRunTime', nmieTotalRunTime)
|
|
|
+
|
|
|
+ } catch (e) {
|
|
|
+ console.log('Some error:', e)
|
|
|
+ }
|
|
|
+ isRunning.value = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ onActivated(()=>{
|
|
|
+ if (isNmieLoaded.value) runNearFieldSimulation()
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return { isRunning, isNmieLoaded,
|
|
|
+ runNearFieldSimulation,
|
|
|
+ saveSpectrumSimulation(){
|
|
|
+ const fileHeader = '# # You can open and plot this file using Python\n' +
|
|
|
+ '# # (without manually removing this header, it will be skipped), see example below.\n' +
|
|
|
+ '# import numpy as np\n' +
|
|
|
+ '# from matplotlib import pyplot as plt\n' +
|
|
|
+ '# data = np.genfromtxt(\'scattnlay-spectra.txt\', skip_header=21, names=True, delimiter=\', \')\n' +
|
|
|
+ '# x = data[data.dtype.names[0]] # x-axis has units\n' +
|
|
|
+ '# # Possible labels for spectrum data: Qsca, Qabs, Qext,\n' +
|
|
|
+ '# # Qsca_E_dipole, etc. (see last comment before spectra data)\n' +
|
|
|
+ '# a = data[\'Qsca\']\n' +
|
|
|
+ '# b = data[\'Qsca_E_dipole\']\n' +
|
|
|
+ '# c = data[\'Qsca_H_dipole\']\n' +
|
|
|
+ '# \n' +
|
|
|
+ '# plt.figure()\n' +
|
|
|
+ '# plt.plot(x, a, label=\'Qsca\')\n' +
|
|
|
+ '# plt.plot(x, b, label=\'Qsca E dipole\')\n' +
|
|
|
+ '# plt.plot(x, c, label=\'Qsca H dipole\')\n' +
|
|
|
+ '# plt.legend()\n' +
|
|
|
+ '# plt.xlabel(data.dtype.names[0].replace(\'_\', \', \'))\n' +
|
|
|
+ '# plt.ylabel(\'Normalized cross-sections\')\n' +
|
|
|
+ '# plt.show()\n\n'
|
|
|
+ let xTitle = 'x'
|
|
|
+ if ( $store.state.plotRuntime.spectrumPlots.layout.xaxis ) {
|
|
|
+ xTitle = String($store.state.plotRuntime.spectrumPlots.layout.xaxis.title)
|
|
|
+ }
|
|
|
+
|
|
|
+ let columnNames = '# ' + xTitle + ', Qsca, Qabs, Qext, '
|
|
|
+ const mode_n = rangeInt($store.state.simulationSetup.current.numberOfModesToPlot, 1);
|
|
|
+ const mode_types = range(0, 1);
|
|
|
+ for (const n of mode_n) {
|
|
|
+ for (const mode_type of mode_types) {
|
|
|
+ const modeTypeName = mode_type == 0 ? 'E' : 'H'
|
|
|
+ columnNames += 'Qsca_' + modeTypeName + '_' +getModeName(n)+', '
|
|
|
+ columnNames += 'Qabs_' + modeTypeName + '_' +getModeName(n)+', '
|
|
|
+ columnNames += 'Qext_' + modeTypeName + '_' +getModeName(n)+', '
|
|
|
+ }
|
|
|
+ }
|
|
|
+ columnNames = columnNames.slice(0, -2)
|
|
|
+ columnNames += '\n'
|
|
|
+ let body = ''
|
|
|
+ const WLs = $store.state.plotRuntime.WLsInUnits
|
|
|
+ const Qsca = $store.state.plotRuntime.Qsca
|
|
|
+ const Qabs = $store.state.plotRuntime.Qabs
|
|
|
+ const Qext = $store.state.plotRuntime.Qext
|
|
|
+ const Qsca_n = $store.state.plotRuntime.Qsca_n
|
|
|
+ const Qabs_n = $store.state.plotRuntime.Qabs_n
|
|
|
+ const Qext_n = $store.state.plotRuntime.Qext_n
|
|
|
+ for (let i = 0; i < WLs.length; ++i) {
|
|
|
+ let row = WLs[i].toString() + ', '
|
|
|
+ + Qsca[i].toString() + ', '
|
|
|
+ + Qabs[i].toString() + ', '
|
|
|
+ + Qext[i].toString() + ', '
|
|
|
+ for (const n of mode_n) {
|
|
|
+ for (const mode_type of mode_types) {
|
|
|
+ row += Qsca_n[mode_type][n - 1][i].toString() + ', '
|
|
|
+ row += Qabs_n[mode_type][n - 1][i].toString() + ', '
|
|
|
+ row += Qext_n[mode_type][n - 1][i].toString() + ', '
|
|
|
+ }
|
|
|
+ }
|
|
|
+ row = row.slice(0, -2)
|
|
|
+ row += '\n'
|
|
|
+ body += row
|
|
|
+ }
|
|
|
+
|
|
|
+ const scattnlaySpectra = new Blob([fileHeader+columnNames+body],
|
|
|
+ {type: 'text/plain;charset=utf-8',
|
|
|
+ endings: 'native'} //TODO test if newline is correctly written in Windows, MacOS
|
|
|
+ )
|
|
|
+ saveAs(scattnlaySpectra, 'scattnlay-spectra.txt');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+})
|
|
|
+</script>
|