FDTD UTILS TUTORIAL

This tutorial covers the core of the python utility package. It includes:

  • The source utils located in source.py file. This code is acts as a python wrapper for C++ execution commands.
  • The analysis utils located in ftdt_utils.py file and written as auxiliary functions to analyze a NANOCPP output.
  • The fractional fitting utils functions also located in ftdt_utils.py file.
  • The shaheen utils functions facilitating working with NANOCPP on shaheen.
  • The color package providing the basic color analysis functionality.

Let's start with importing the dependencies to run this tutotial interactively with Jupyter.

In [1]:
import os, sys
from matplotlib import pyplot as plt
import numpy as np
import math
from scipy.optimize import curve_fit
from scipy.signal import residue
import random as rnd
import sympy
import geometryproc
from geometryproc import Geometry
In [2]:
from importlib import reload
os.chdir('/home/makam0a/projects/nanocpp-extras/examples/test_utils/')

STRUCTURE

This package provides you with a several methods which can assist in your research based on NANOCPP.

Source code

In order to simplify some basic NANOCPP operations, we provide you with some auxillary classes in source.py file. The basic examples of usage you can find in test.py file. In general, instead of createing executable string by yourself, you can use class run_fdtd from this package.

  1. Import run_fdtd and preferable source type from sources.
from sources import cw, spl, fcb, run_fdtd
  1. Specify NANOCPP options
fdtd_args = {
        'box_size' : [wx,wz],
        'number_of_cells' : [dimx,dimz],
        'tfsf_box' : a,
        'exefile' : 'nano',
        'total_steps' : 25000,
        'io_screen' : 10000,
        'erg_io' : 10000,
        'upml' : upml,
        'base_dir' : resdir,
        'media_file' : 'geometry.txt',
        'source' : spl(0.5),
        'shaheen_kargs' : {}
    }
  1. (b) If you are running this on Shaheen and wanted to specify non-default options you can do it by creating a dictionary and pass it as shaheen_kargs.
shaheen_kargs = {
        'queue' : 'debug,
        'outputdir' : '.shaheen',
        'resdir' : '.',
        'datadir' : '.',
        'time' : '00:30:00',
        'ntasks' : 32,
        'files_to_check' : None,
        'string_to_check' : None,
        'separator' : ' && ',
        'print_warning' : True,
        'try_relaunch' : True
    }

In this particular example all default options are listed. By default your command line would be "freezed" until the job disappears from the queue. You can add some other way of controlling your simulations, by specifying 'files_to_check' argument which should contain a list of files which creation should indicate that your job have been finished, or
'string_to_check' argument, which is checking wether specific string in the output appeared. By default there is some warnings being printed in strange cases which most probably indicates that your job have been finished unsuccessfully. For instance, if your job is not in queue anymore, but files specified on files_to_check list have not been created.

  1. Create run_fdtd object and pass your dictionary into it.
sim = run_fdtd(**fdtd_args)
  1. (a) If you need to compile your project, you can call corresponding method from an instance
sim.compile()
  1. (b) Run your simulation by calling the corresponing method
sim.run()

As simple as that.

Analysis

Harmonic analysis

In many cases it is desirable to measure the reflection/transmission at different frequencies and obtain the corresponding spectra. One approach is to launch different simulations by using cw sources at different frequencies. This solution takes typically time especially when high spectral resolution is needed. When the dispersion curve of the material is known, a much more effective approach can be developed by using a broadband SPL input source, which behaves as a dirac delta in time an probe the density of states of the system in a continnum set of frequencies. The main issue of this approach is how to measure the energy, which is a nonlinear operator involving products of $\mathbf{E}$ and $\mathbf{H}$ fields. The presence of products require to store in memory the time evolution each component of the field in each point of integration. The corresponding data can be quite large, especially in 3D. To avoid this problem an enable an efficient analysis in NANOCPP, we took inspiration from JPEG compression of data and use an orthogonal, complete basis of cosine functions:

$$c_n=A_n\cos(n\pi x/L)$$

with normalization constants A_n defined on the integration length L, to store all temporal information of the electromagnetic fields needed for power flow computations. NANOCPP automatically calculates the time expansion coefficients and save them in an appropriate matrix file, which can be then easily analyzed. This main advantage of this approach is that it typically converge with just a few cosine frequencies (less than 10 for accuracy < 1%).

In order to assist you with that fdtd_utils supplied with harm analysis class.

In [3]:
def reload_fdtd():
    global tdcmt, myfun, frac_fit, exp_fit, disp_fit, mt, unpack, harm
    import fdtd_utils
    reload(fdtd_utils)
    import materials as mt
    import colors
    reload(mt)
    reload(colors)
    from fdtd_utils import tdcmt
    from fdtd_utils import myfun
    from fdtd_utils import frac_fit
    from fdtd_utils import exp_fit
    from fdtd_utils import disp_fit
    from fdtd_utils import unpack
    from fdtd_utils import harm

Let's consider simple silicon slab and calculate its transmission.

In [4]:
resdir = 'res/'
import geometryproc
reload(geometryproc)
from geometryproc import Geometry
Geometry(resdir+'geometry.txt', xlim=(0.0,0.8), zlim = (0.0, 2.0)).draw(show=True)
In [5]:
reload_fdtd()
transm = harm(resdir+'hsrc.bin', resdir+'hful.bin', 5.85482e-12, 50000, 2)
In [6]:
plt.plot(1/transm.wl,transm.transm[:,0])
plt.xlim(0,5)
plt.ylim(0)
plt.show()

DOS analysis

One of the most important quantities of a resonance system is so-called density of states (DOS). The density of states of a system could be defined as

$$ \begin{equation}\label{Eq.31} \operatorname{DOS}(\omega)=\sum_{n} \delta\left(\omega-\omega^{(n)}\right) \end{equation} $$

This quantity basically represents number of states of your system per energy interval.

To calculate this quantity in NANOCPP we use approach similar to the one described in the previous section, but in this case we surround our structure with perpendicular grid on which we decompose electromagnetic field on orthogonal functions.

You can do it easily using tdcmt class provided in fdtd_utils.py.

In [47]:
resdir = 'res/'
reload_fdtd()
spectr = tdcmt(resdir+'src.bin',resdir+'ful.bin',5.85482e-12,50000)
plt.plot(spectr.f,spectr.dos)
plt.xlim(0,5)
plt.show()

Shaheen

To run series jobs on shaheen you don't need to do any extra work, you can do exactly the same thing you did in your local machine with run_fdtd class.

But if you need to do some parallel computing with controlling of multiple jobs, you could use sim_list class from shaheen.py file. This class basically represents a list of simulations with couple reloaded operators. sach as check sims (check if whole list of simulations have come to an end) and submit (all simulations in the list). Below you can find very simple example of how toc use this script to launch and control multiple simulations on shaheen.

sims = sim_list()
    exe_strgs = []
    final_string = 'Finished!'
    for i in range(10):
        fname = 'test-%i.out' % i
        exe_strgs.append("echo %d" % i)
        exe_strgs.append('sleep %d' % int(3*i))
        exe_strgs.append('echo "%s"' % final_string)
        sim = single_sim('test_%d' % i,exe_strgs,files_to_check=[fname],string_to_check=final_string,try_relaunch=False)
        sims.append(sim)
    sims.clean()
    sims.submit()
    sims.check_sims(2)
    print(sims[:3])

the only confusing place can be clean function. This function is responsible for renaming (deleting) control files, files you are using to identify whether job have been successfully finished or not.

Colors

In addition fdtd_utils provides some basic operations on colors using colour-science package. There is two basic operations: getting the color (RGB or CIE) from spectra and getting spectra from CIE color.

This operations for the sake of convenience were implemented in harm class and you can easily get reflective and transmittive spectra just simply call corresponding method.

In [61]:
print(transm.get_color())
transm.color.plot_cie()
transm.color.plot_rgb()
[ 0.25731165  0.40960194]