This tutorial covers the core of the python utility package. It includes:
Let's start with importing the dependencies to run this tutotial interactively with Jupyter.
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
from importlib import reload
os.chdir('/home/makam0a/projects/nanocpp-extras/examples/test_utils/')
This package provides you with a several methods which can assist in your research based on NANOCPP.
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.
from sources import cw, spl, fcb, run_fdtd
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' : {}
}
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.
sim = run_fdtd(**fdtd_args)
sim.compile()
sim.run()
As simple as that.
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.
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.
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)
reload_fdtd()
transm = harm(resdir+'hsrc.bin', resdir+'hful.bin', 5.85482e-12, 50000, 2)
plt.plot(1/transm.wl,transm.transm[:,0])
plt.xlim(0,5)
plt.ylim(0)
plt.show()
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.
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()
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.
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.
print(transm.get_color())
transm.color.plot_cie()
transm.color.plot_rgb()