Simulation results are typically stored in datasets simulation or monitor objects Lumerical products. This article will describe how datasets and raw simulation data can be accessed and processed when using the Python API.
For more information on how basic datatypes are translated and best practices when transferring data, see the Knowledge Base article Passing Data in Python API, for more information on Lumerical datasets, see the Knowledge Base article Introduction to Lumerical Datasets.
Accessing Datasets
Datasets are relevant results that have been packaged in a form that makes it possible to readily visualize and explore in Lumerical. These datasets can be passed into the Python workspace using the getresult() method.
When datasets are returned into the Python environment, they will be converted into dictionaries, with keys associated with various attributes and parameters.
Dictionaries converted from datasets will have a special metadata key 'Lumerical_dataset' which contains identifier values, allows their structure to be preserved when performing a roundtrip back to the Lumerical environment. When passing a dictionary from Python to Lumerical it will be converted into a structure, unless it has the metadata element.
Attributes and parameters are both stored as numpy arrays in Python. Parameters are 1-D arrays that acts as a list of parameters. For attributes, the dimension of the array depends on the type of dataset, the type of data, and the number of parameters.
Dataset Type | Attribute Dimensions |
Matrix Dataset |
Dimensions depend on type of attribute:
where \(N_{pi}\) is the length of the \(i\)th parameter. |
Rectilinear Dataset |
Dimensions depend on type of attribute:
where \(N_k, k = x, y, z\) are the lengths of the coordinate vectors, and \(N_{pi}\) is the length of the \(i\)th parameter. If the dataset is 2D or 1D, then you will have singleton dimensions, so that one of \(N_k = 1\). |
Unstructured Dataset |
Dimensions depend on type of attribute:
where \(N_N\) is the number of elements in the unstructured grid. An extra attribute for the grid connectivity array, named |
Note: Singleton dimensions can be removed with the pinch() command or the squeeze method in numpy.
Example
The following example uses an example file ‘fdtd_file.fsp’ created using the following script, this file can also be found attached to this article.
from collections import OrderedDict import lumapi with lumapi.FDTD() as fdtd: fdtd.addfdtd(dimension="2D", x=0.0e-9, y=0.0e-9, x_span=3.0e-6, y_span=1.0e-6) fdtd.addgaussian(name = 'source', x=0., y=-0.4e-6, injection_axis="y", waist_radius_w0=0.2e-6, wavelength_start=0.5e-6, wavelength_stop=0.6e-6) fdtd.addring( x=0.0e-9, y=0.0e-9, z=0.0e-9, inner_radius=0.1e-6, outer_radius=0.2e-6, index=2.0) fdtd.addmesh(dx=10.0e-9, dy=10.0e-9, x=0., y=0., x_span=0.4e-6, y_span=0.4e-6) fdtd.addtime(name="time", x=0.0e-9, y=0.0e-9) fdtd.addprofile(name="profile", x=0., x_span=3.0e-6, y=0.) # Dict ordering is not guaranteed, so if there properties dependant on other properties an ordered dict is necessary # In this case 'override global monitor settings' must be true before 'frequency points' can be set props = OrderedDict([("name", "power"), ("override global monitor settings", True), ("x", 0.),("y", 0.4e-6),("monitor type", "linear x"), ("frequency points", 10.0)]) fdtd.addpower(properties=props) fdtd.save("fdtd_file.fsp")
The following script uses this file to obtain rectilinear datasets.
import lumapi with lumapi.FDTD('fdtd_file.fsp') as fdtd: fdtd.run() #Return 2 different types of rectilinear datasets T, time = fdtd.getresult("power", "T"), fdtd.getresult("time","E") print('Transmission result T is type', type(T),' with keys', str(T.keys()) ) print('Time monitor result E is type', type(time),' with keys', str(time.keys()) )
Returns
Transmission result T is type <class 'dict'> with keys dict_keys(['lambda', 'f', 'T', 'Lumerical_dataset'])
Time monitor result E is type <class 'dict'> with keys dict_keys(['t', 'x', 'y', 'z', 'E', 'Lumerical_dataset'])
The following script creates a p-n junction in Lumerical Multiphysics, and returns an unstructured dataset related to its doping.
from collections import OrderedDict import lumapi with lumapi.DEVICE() as device: #Create Simulation region device.addsimulationregion(name = "SimRegion", dimension = "2D Y-Normal", x_span = 1.5e-6, z_span = 0.5e-6) device.addchargesolver(name = "CHARGE", simulation_region = "SimRegion") #Add materials device.addmodelmaterial(name = "Silicon") device.addmaterialproperties("CT","Si (Silicon)") #Add Geometry device.addrect(name = "junction", x_span = 2e-6, y_span = 1e-6, z_span = 0.5e-6, material = "Silicon") #Add Doping device.adddope(name ="n dope", x_min = -1e-6, x_max = 0, dopant_type = "n", concentration = 1e16) device.adddope(name ="p dope", x_min = 0, x_max = 1e-6, dopant_type = "p", concentration = 1e16) #Add Contacts prop_n_contact = OrderedDict([("name", "n_contact"), ("surface type", "simulation region"), ("x min", True)]) device.addelectricalcontact(properties = prop_n_contact) prop_p_contact = OrderedDict([("name", "p_contact"), ("surface type", "simulation region"), ("x max", True)]) device.addelectricalcontact(properties = prop_p_contact) #Save File device.save("UnstructuredDatasetTest.ldev") #mesh and get doping results device.mesh() unstructured_result = device.getresult("CHARGE","grid") print(f"unstructured_result is of type {type(unstructured_result)} and contains {unstructured_result.keys()}")
Returns
unstructured_result is of type <class 'dict'> and contains dict_keys(['area', 'ID', 'x', 'y', 'z', 'connectivity', 'N', 'Lumerical_dataset'])
Accessing Raw Data
Raw data from monitors are results in their raw, matrix form. These results can also be passed to the Python workspace using the getdata() command.
Raw data are matrices in Lumerical products and will be returned as numpy arrays when passed to the Python environment. The dimensions of attributes and
The length to each dimension of the returned array depends on whether the raw data was originally an attribute or parameter. These dimensions follow the dimensions for attributes and parameters described in the “Accessing Dataset” section above.
Example
The following example uses the FDTD project file “fdtd_file.fsp” created above and accesses raw data stored in the profile monitor.
import lumapi with lumapi.FDTD('fdtd_file.fsp') as fdtd: fdtd.run() #Return raw E field data Ex = fdtd.getdata("profile","Ex") f = fdtd.getdata("profile","f") x = fdtd.getdata("profile","x") y = fdtd.getdata("profile","y") print('Frequency field profile data Ex is type', type(Ex),' with shape', str(Ex.shape)) print('Frequency field profile data f is type', type(f), 'with shape', str(f.shape)) print('Frequency field profile data x is type', type(x), 'with shape', str(x.shape)) print('Frequency field profile data y is type', type(y), 'with shape', str(y.shape))
Returns
Frequency field profile data Ex is type with shape (99, 59, 1, 5) Frequency field profile data f is type with shape (5, 1) Frequency field profile data x is type with shape (99, 1) Frequency field profile data y is type with shape (59, 1)
See Also
Python API Overview, Working with Simulation Objects – Python API, Script Commands as Methods – Python API. Installation and Getting Started – Python API, Passing Data – Python API