Browse Source

add plotting of material data, keep-alive components, tune publicPath handling

Konstantin Ladutenko 3 years ago
parent
commit
08df00f660

+ 10 - 4
guiapp/quasar.conf.js

@@ -53,10 +53,16 @@ module.exports = configure(function (ctx) {
 
     // Full list of options: https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
     build: {
-      publicPath: process.env.NODE_ENV === 'production'
-          ? '/themes/custom/physics/mie-next/' //deploy path in Drupal setup at physics.ifmo.ru
-          : '/',
-
+      publicPath: process.env.NODE_ENV === 'development'
+          ? '/'
+          : '/themes/custom/physics/mie-next/', //deploy path in Drupal setup at physics.ifmo.ru
+
+      env: {
+        // copy publicPath from above build.publicPath to make it available from inside of the app.
+        publicPath: ctx.dev
+            ? '/'
+            : '/themes/custom/physics/mie-next/' //deploy path in Drupal setup at physics.ifmo.ru
+      },
       // extendWebpack (cfg, { isServer, isClient }) {
       //   cfg.module.rules.push({
       //     enforce: 'pre',

+ 10 - 6
guiapp/src/components/MaterialsActivated.vue

@@ -35,25 +35,29 @@
 
           <q-td auto-width>
             <q-checkbox :model-value="props.row.isPlot" size="sm" color="primary" dense
-                        @click="$store.commit('guiRuntime/toggleIsPlot',
-                        props.row.name
-                        )"
+                        @click="$store.commit('guiRuntime/toggleIsPlot', props.row.name )"
             />
           </q-td>
 
 
-          <q-td auto-width class="">
+          <q-td auto-width class=""
+                @click="$store.commit('guiRuntime/toggleIsPlot', props.row.name )"
+          >
             {{composeLabelFromPageData(props.row.name)}}
           </q-td>
 
-          <q-td auto-width>
+          <q-td auto-width
+                @click="$store.commit('guiRuntime/toggleIsPlot', props.row.name )"
+          >
             <ShowSpectrumRange
                 :spectrum-range-start="props.row.spectrumRangeStart"
                 :spectrum-range-end="props.row.spectrumRangeEnd"
             />
           </q-td>
 
-          <q-td class="">
+          <q-td class=""
+                @click="$store.commit('guiRuntime/toggleIsPlot', props.row.name )"
+          >
             <span v-if="props.row.nSpline && props.row.kSpline">
               <q-icon size='sm' color="green" name="done" />
             </span>

+ 3 - 3
guiapp/src/components/MaterialsSelector.vue

@@ -153,10 +153,10 @@ export default defineComponent({
 
       let rows = []
       // lib has an irregular structure
-      const response = await fetch('refractiveindex.info-database/database/library.yml')
+      const response = await fetch(process.env.publicPath+'refractiveindex.info-database/database/library.yml')
       const data = await response.text()
 
-      const response2 = await fetch('tabulated.txt')
+      const response2 = await fetch(process.env.publicPath+'tabulated.txt')
       const tabulated = await response2.text()
 
       const lib = await load(data) as any
@@ -239,7 +239,7 @@ export default defineComponent({
         $store.dispatch('guiRuntime/activateMaterial', rows[val-1].pageData)
       },
       async downloadPageData(filepath:string) {
-        const response = await fetch('refractiveindex.info-database/database/data/'+filepath)
+        const response = await fetch(process.env.publicPath+'refractiveindex.info-database/database/data/'+filepath)
         const data = await response.text()
 
         const scattnlaySpectra = new Blob([data],

+ 121 - 0
guiapp/src/components/PlotMaterials.vue

@@ -0,0 +1,121 @@
+<template>
+  <div>
+    <div class="row items-baseline">
+      <div class="col-xs-12 col-sm-auto text-weight-bold text-center q-px-md q-py-sm">
+        <div :style="flexRowTitleStyle">
+          Plot options
+        </div>
+      </div>
+      <div class="col-xs-grow col-sm">
+        <div class="row justify-xs-center justify-sm-start items-center">
+          <div class="col-auto" >select data: </div>
+          <div class="col-auto" ><q-toggle v-model="isPlotReN">Re(n)</q-toggle></div>
+          <div class="col-auto" ><q-toggle v-model="isPlotImN">Im(n)</q-toggle></div>
+          <div class="col-auto" ><q-toggle v-model="isPlotInterpolation">Interpolation</q-toggle></div>
+
+        </div>
+      </div>
+    </div>
+
+    <div class="row items-baseline">
+      <div class="col-xs-12 col-sm-auto text-weight-bold text-center q-px-md q-py-sm">
+        <div :style="flexRowTitleStyle">
+
+        </div>
+      </div>
+      <div class="col-xs-grow col-sm">
+        <div class="row justify-xs-center justify-sm-start items-baseline">
+          <div class="col-auto q-pr-md" >interpolation range from: </div>
+          <div class="col-auto">
+            <div class="q-gutter-x-md">
+              <q-radio v-model="plotRange" dense size='sm' val="material data" label="material data" />
+              <q-radio v-model="plotRange" dense size='sm' val="simulation settings" label="simulation settings" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <ReactiveChart :chart="$store.state.plotRuntime.materialPlots"/>
+  </div>
+</template>
+
+<script>
+import ReactiveChart from 'components/ReactiveChart.vue'
+import { useStore } from 'src/store'
+import {
+  defineComponent,
+  onActivated,
+  ref,
+  computed,
+  watch
+} from 'vue'
+import { flexRowTitleStyle } from 'components/config'
+
+
+export default defineComponent({
+  name: 'PlotMaterials',
+  components: {
+    ReactiveChart,
+  },
+  setup () {
+    const $store = useStore()
+
+    const sourceUnits = computed( ()=>$store.state.guiRuntime.sourceUnits)
+    function setPlotTitle() {
+      let title=''
+      if (sourceUnits.value.endsWith('Hz')) {
+        title = 'Frequency [' + sourceUnits.value + ']'
+      } else if (sourceUnits.value.endsWith('eV')) {
+        title = 'Energy [' + sourceUnits.value + ']'
+      } else if (sourceUnits.value.endsWith('s')) {
+        title = 'Period [' + sourceUnits.value + ']'
+      } else {
+        title = 'Wavelength [' + sourceUnits.value + ']'
+      }
+      $store.commit('plotRuntime/updateXAxisTitle', title)
+    }
+
+
+    const plotRange=ref('material data')
+    const isPlotReN = ref(true)
+    const isPlotImN = ref(true)
+    const isPlotInterpolation = ref(true)
+
+    const fromWL = computed(()=>$store.state.simulationSetup.gui.fromWL)
+    const toWL = computed(()=>$store.state.simulationSetup.gui.toWL)
+    const pointsWL = computed(()=>$store.state.simulationSetup.gui.pointsWL)
+    function updateSpectraPlot() {
+      setPlotTitle()
+
+      $store.commit('plotRuntime/updateMaterialPlots',
+          {
+            activatedMaterials: $store.state.guiRuntime.activatedMaterials,
+            sourceUnits: sourceUnits.value,
+            fromWL: fromWL.value,
+            toWL: toWL.value,
+            pointsWL: pointsWL.value,
+            plotRange: plotRange.value,
+            isPlotReN: isPlotReN.value,
+            isPlotImN: isPlotImN.value,
+            isPlotInterpolation: isPlotInterpolation.value
+          })
+    }
+    updateSpectraPlot()
+
+    const materialsToPlot=computed(()=>$store.state.guiRuntime.activatedMaterials
+        .filter((val)=>val.isPlot)
+        .map(val=>val.name))
+
+    watch ([materialsToPlot, plotRange, isPlotReN, isPlotImN, isPlotInterpolation], ()=>{
+      updateSpectraPlot()
+    })
+
+    onActivated(()=>updateSpectraPlot())
+
+    return { flexRowTitleStyle,
+    isPlotReN, isPlotImN, isPlotInterpolation,
+    plotRange}
+  }
+})
+</script>

+ 14 - 1
guiapp/src/components/PlotSelector.vue

@@ -5,6 +5,11 @@
         remove previous spectra
       </q-checkbox>
     </div>
+    <div class="col-auto q-py-xs q-px-sm">
+      <q-checkbox v-model="isLogPlot" size="sm">
+        plot cross-sections in log scale
+      </q-checkbox>
+    </div>
   </div>
   <div class="row items-baseline">
     <div class="col-xs-grow col-sm-auto q-px-sm">
@@ -95,6 +100,14 @@ export default defineComponent({
       }
     })
 
+    const isLogPlot = computed({
+      get: ()=> $store.state.plotRuntime.isLogPlot,
+      set: val => {
+        $store.commit('plotRuntime/setIsLogPlot', val)
+        $store.commit('plotRuntime/updateSpectrumPlots')
+      }
+    })
+
     const isPlotQsca = computed({
       get: () => $store.state.plotRuntime.isPlotQsca,
       set: val => $store.commit('plotRuntime/setQscaPlotToggle', val)
@@ -223,7 +236,7 @@ export default defineComponent({
     )
 
     return {flexRowTitleStyle,
-      isRemovePlots,
+      isRemovePlots, isLogPlot,
       isPlotQsca, isPlotQabs, isPlotQext,
       guiNumberOfModes, simulatedNumberOfModes,
       columns, rows,

+ 14 - 3
guiapp/src/components/ReactiveChart.vue

@@ -8,6 +8,7 @@ import { plotlyChart } from 'src/store/plot-runtime/state'
 import {
   defineComponent,
   PropType,
+  onActivated,
   watch,
   onMounted,
   onUnmounted,
@@ -25,11 +26,13 @@ export default defineComponent({
   },
   setup(props) {
     const chartUUID = uuidv4()
+    // const chartUUID = 'plotly chart'
     let chartLocal = cloneDeep(props.chart)
 
     // Update (or add if absent) width and height of the layout to fit current window
     // and replot it.
     function plotlyReact () {
+      if (!document.getElementById(chartUUID)) return
       const width = window.innerWidth
       const height = window.innerHeight*0.8
       chartLocal.layout.width = width * 0.92
@@ -44,12 +47,15 @@ export default defineComponent({
       }
     }
 
-    onMounted( async () => {
+    function plotlyNew() {
       if (chartLocal.config == undefined) {
-        await newPlot(chartUUID, chartLocal.data, chartLocal.layout)
+        void newPlot(chartUUID, chartLocal.data, chartLocal.layout)
       } else {
-        await newPlot(chartUUID, chartLocal.data, chartLocal.layout, chartLocal.config)
+        void newPlot(chartUUID, chartLocal.data, chartLocal.layout, chartLocal.config)
       }
+    }
+    onMounted( () => {
+      plotlyNew()
     })
 
     window.addEventListener('resize', plotlyReact)
@@ -62,6 +68,11 @@ export default defineComponent({
       plotlyReact()
     })
 
+    onActivated(()=>{
+      chartLocal = cloneDeep(props.chart)
+      plotlyReact()
+    })
+
     return {
       chartUUID
     }

+ 11 - 0
guiapp/src/components/RunSimulationSpectrum.vue

@@ -32,6 +32,7 @@
 import {
   defineComponent,
   computed, watch,
+    onActivated
 } from 'vue'
 import { useStore } from 'src/store'
 import { getModeName, range, rangeInt} from 'components/utils'
@@ -160,6 +161,16 @@ export default defineComponent({
       if (isNmieLoaded.value) runSpectrumSimulation()
     })
 
+    onActivated(()=>{
+      if (isNmieLoaded.value) {
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-ignore
+        // eslint-disable-next-line
+        const data_x_length = $store.state.plotRuntime.spectrumPlots.data[0].x.length
+        if (!data_x_length) runSpectrumSimulation()
+      }
+    })
+
     return { isRunning, isNmieLoaded,
       runSpectrumSimulation,
       saveSpectrumSimulation(){

+ 9 - 1
guiapp/src/layouts/MainLayout.vue

@@ -84,7 +84,15 @@
     </q-drawer>
 
     <q-page-container>
-      <router-view />
+<!--      <router-view />-->
+      <router-view v-slot="{ Component }">
+<!--        <transition name="fade">-->
+          <keep-alive>
+            <component :is="Component" />
+          </keep-alive>
+<!--        </transition>-->
+      </router-view>
+
     </q-page-container>
   </q-layout>
 </template>

+ 5 - 0
guiapp/src/pages/Far-field.vue

@@ -6,6 +6,11 @@
     <div class="col-auto">
       Input result: {{$store.state.simulationSetup.gui.fromWL}}
     </div>
+
+    <!-- place QPageScroller at end of page -->
+    <q-page-scroller position="bottom-right" :scroll-offset="150" :offset="[18, 18]">
+      <q-btn size="xs" fab icon="keyboard_arrow_up" color="primary" />
+    </q-page-scroller>
   </q-page>
 </template>
 

+ 4 - 0
guiapp/src/pages/Materials.vue

@@ -8,6 +8,10 @@
     <div class="q-ma-xs"/>
     <PlotMaterials/>
     <div class="q-ma-xs"/>
+    <!-- place QPageScroller at end of page -->
+    <q-page-scroller position="bottom-right" :scroll-offset="150" :offset="[18, 18]">
+      <q-btn size="xs" fab icon="keyboard_arrow_up" color="primary" />
+    </q-page-scroller>
   </q-page>
 </template>
 

+ 8 - 2
guiapp/src/pages/Near-field.vue

@@ -1,7 +1,7 @@
 <template>
   <q-page class="column q-px-md">
 <!--    <img src="https://www.pikpng.com/pngl/m/8-80773_new-content-coming-soon-website-under-construction-banner.png" alt="New Content Coming Soon - Website Under Construction">-->
-    <q-img src="underconstruction.jpg"  />
+    <q-img :src="img_path"  />
     <div class="q-ma-sm"/>
     Under construction!
 
@@ -11,6 +11,10 @@
     <div class="col-auto">
       Input result: {{$store.state.simulationSetup.gui.fromWL}}
     </div>
+    <!-- place QPageScroller at end of page -->
+    <q-page-scroller position="bottom-right" :scroll-offset="150" :offset="[18, 18]">
+      <q-btn size="xs" fab icon="keyboard_arrow_up" color="primary" />
+    </q-page-scroller>
   </q-page>
 </template>
 
@@ -30,8 +34,10 @@ export default defineComponent({
     // GetParticleParameters
   },
   setup() {
+    let img_path = 'underconstruction.jpg'
+    if (process.env.publicPath) img_path = process.env.publicPath.toString()+'underconstruction.jpg'
     // const $store = useStore()
-    return {}
+    return {img_path}
   }
 })
 </script>

+ 5 - 0
guiapp/src/pages/Spectrum.vue

@@ -21,6 +21,11 @@
     <PlotSelector/>
     <div class="q-ma-xs"/>
     <PlotSpectra/>
+
+    <!-- place QPageScroller at end of page -->
+    <q-page-scroller position="bottom-right" :scroll-offset="150" :offset="[18, 18]">
+      <q-btn size="xs" fab icon="keyboard_arrow_up" color="primary" />
+    </q-page-scroller>
   </q-page>
 </template>
 

+ 2 - 1
guiapp/src/store/gui-runtime/actions.ts

@@ -14,7 +14,8 @@ async function loadMaterialData(filename:string):Promise<number[][] | undefined>
   let Ag_data
 
   try {
-    const response = await fetch('refractiveindex.info-database/database/data/'+filename)
+    console.log('Public path:', process.env.publicPath)
+    const response = await fetch(process.env.publicPath+'refractiveindex.info-database/database/data/'+filename)
     const Ag_data = await response.text()
 
     const doc = await load(Ag_data) as any

+ 95 - 2
guiapp/src/store/plot-runtime/mutations.ts

@@ -1,8 +1,9 @@
 import { MutationTree } from 'vuex'
 import { cloneDeep } from 'lodash'
-import { Data } from 'plotly.js-dist-min'
+import {AxisType, Data} from 'plotly.js-dist-min'
 import { plotRuntimeStateInterface as prsi, spectraData } from './state'
 import { getModeName, toUnits } from 'components/utils'
+import { material } from 'src/store/simulation-setup/state'
 
 
 const mutation: MutationTree<prsi> = {
@@ -29,6 +30,7 @@ const mutation: MutationTree<prsi> = {
   setQabsTotalPlotToggle (state: prsi, val: boolean) {state.isPlotQabsTotal = val},
   setQextTotalPlotToggle (state: prsi, val: boolean) {state.isPlotQextTotal = val},
   setIsRemovePlots (state:prsi, val:boolean) {state.isRemovePlots = val},
+  setIsLogPlot (state:prsi, val:boolean) {state.isLogPlot = val},
   setCommonLabel  (state:prsi, val:string) {state.commonLabel = val},
 
   resizeSelectorIsPlotMode (state:prsi, val:number) {
@@ -46,6 +48,7 @@ const mutation: MutationTree<prsi> = {
 
   updateXAxisTitle (state:prsi, val:string) {
     if (state.spectrumPlots.layout.xaxis) state.spectrumPlots.layout.xaxis.title = val
+    if (state.materialPlots.layout.xaxis) state.materialPlots.layout.xaxis.title = val
   },
 
   updateNumberOfPlotsFromPreviousSimulations(state: prsi) {
@@ -54,6 +57,9 @@ const mutation: MutationTree<prsi> = {
   updateSpectrumPlots (state: prsi) {
     if (state.isRemovePlots) state.numberOfPlotsFromPreviousSimulations = 0
     state.spectrumPlots.data.length = state.numberOfPlotsFromPreviousSimulations
+    let logState:AxisType|undefined = undefined
+    if (state.isLogPlot) logState = 'log'
+    if (state.spectrumPlots.layout.yaxis) state.spectrumPlots.layout.yaxis.type = logState
 
     const label:string = state.commonLabel
     if (state.isPlotQscaTotal) {
@@ -122,9 +128,96 @@ const mutation: MutationTree<prsi> = {
         }
       }
     }
+  },
 
+  // TODO move state.materialPlots and updateMaterialPlots to PlotMaterials.vue. At the moment
+  // *.vue have incomplete TypeScript support (e.g. no way to define
+  //     const traceDataReN: Partial<Data>
+  // )
+  updateMaterialPlots(state:prsi, val:{activatedMaterials:material[], sourceUnits:string,
+    fromWL:number, toWL:number, pointsWL:number, plotRange: string,
+    isPlotReN: boolean, isPlotImN: boolean, isPlotInterpolation: boolean })
+  {
+    state.materialPlots.data.length = 0
+    for (const material of val.activatedMaterials) {
+      if (!material.isPlot) continue
+
+      if (!material.nSpline) continue
+      if (val.isPlotReN) {
+        const traceDataReN: Partial<Data> = {
+          x: material.nSpline.xs.map(x => toUnits(x, val.sourceUnits)),
+          y: material.nSpline.ys,
+          mode: 'markers',
+          marker:{size:5},
+          type: 'scatter',
+          name: 'Re(n) ' + material.name + ' data'
+        }
+        state.materialPlots.data.push(traceDataReN)
+      }
 
-  },
+      if (!material.kSpline) continue
+      if (val.isPlotImN) {
+        const traceDataImN: Partial<Data> = {
+          x: material.kSpline.xs.map(x => toUnits(x, val.sourceUnits)),
+          y: material.kSpline.ys,
+          mode: 'markers',
+          marker:{size:5},
+          type: 'scatter',
+          name: 'Im(n) ' + material.name + ' data'
+        }
+        state.materialPlots.data.push(traceDataImN)
+      }
+
+      if (val.isPlotInterpolation) {
+        let fromWL = val.fromWL
+        let toWL = val.toWL
+        let pointsWL = val.pointsWL-1
+        if (state.materialPlots.layout.xaxis) state.materialPlots.layout.xaxis.range = [fromWL, toWL]
+        if (val.plotRange == 'material data') {
+          fromWL = material.nSpline.xs[0]
+          toWL = material.nSpline.xs[material.nSpline.xs.length-1]
+          pointsWL = 1000
+          if (state.materialPlots.layout.xaxis) state.materialPlots.layout.xaxis.range = undefined
+        }
+        const stepWL = (toWL-fromWL)/pointsWL
+
+        const WLs:number[] =[]
+        const nSpline:number[] = []
+        const kSpline:number[] = []
+        for (let i=0; i<pointsWL; ++i) {
+          WLs.push(fromWL+i*stepWL)
+          nSpline.push(material.nSpline.at(fromWL+i*stepWL))
+          kSpline.push(material.kSpline.at(fromWL+i*stepWL))
+        }
+        WLs.push(toWL)
+        nSpline.push(material.nSpline.at(toWL))
+        kSpline.push(material.kSpline.at(toWL))
+
+        if (val.isPlotReN) {
+          if (!material.nSpline) continue
+          const traceDataReNi: Partial<Data> = {
+            x: WLs.map(x => toUnits(x, val.sourceUnits)),
+            y: nSpline,
+            type: 'scatter',
+            name: 'Re(n) ' + material.name + ' interpolate'
+          }
+          state.materialPlots.data.push(traceDataReNi)
+        }
+
+        if (val.isPlotImN) {
+          if (!material.nSpline) continue
+          const traceDataImNi: Partial<Data> = {
+            x: WLs.map(x => toUnits(x, val.sourceUnits)),
+            y: kSpline,
+            type: 'scatter',
+            name: 'Im(n) ' + material.name + ' interpolate'
+          }
+          state.materialPlots.data.push(traceDataImNi)
+        }
+
+      }
+    }
+  }
 
 }
 

+ 32 - 2
guiapp/src/store/plot-runtime/state.ts

@@ -27,6 +27,7 @@ export interface plotRuntimeStateInterface {
   Qabs_n:number[][][]
   Qext_n:number[][][]
   spectrumPlots: plotlyChart
+  materialPlots: plotlyChart
   isPlotQsca: boolean
   isPlotQabs: boolean
   isPlotQext: boolean
@@ -36,6 +37,7 @@ export interface plotRuntimeStateInterface {
   isPlotModeE: boolean[]
   isPlotModeH: boolean[]
   isRemovePlots: boolean
+  isLogPlot:boolean
   numberOfPlotsFromPreviousSimulations:number
   commonLabel:string
 }
@@ -89,13 +91,41 @@ function state(): plotRuntimeStateInterface {
       displaylogo: false}
   }
   const isRemovePlots = true
+  const isLogPlot = false
+  const materialPlots:plotlyChart = {
+    data: [],
+    layout: {
+      margin: {
+        l: 0,
+        r: 40,
+        b: 50,
+        t: 30
+      },
+      xaxis: {
+        title: ''
+      },
+      yaxis: {
+        title: 'Refractive index'
+      },
+      showlegend: true,
+      legend: {
+        orientation: 'h',
+        x: -.1,
+        y: 1.05
+      },
+    },
+    config: {responsive: true,
+      // showEditInChartStudio: true,
+      displaylogo: false}
+  }
 
   return { WLs, WLsInUnits,
     Qsca, Qabs, Qext, Qsca_n, Qabs_n, Qext_n,
-    spectrumPlots, isPlotQsca, isPlotQabs, isPlotQext,
+    spectrumPlots, materialPlots,
+    isPlotQsca, isPlotQabs, isPlotQext,
     isPlotQscaTotal, isPlotQabsTotal, isPlotQextTotal,
     isPlotModeE, isPlotModeH,
-    isRemovePlots, numberOfPlotsFromPreviousSimulations,
+    isRemovePlots, isLogPlot, numberOfPlotsFromPreviousSimulations,
     commonLabel
   }
 }