Putting data into VNL files is simple in NanoLanguage, using the
addToSample() function, and appears to be a convenient way of storing data calculated by ATK. However, getting it out again can be a challenge (which kind of makes the idea of using it for storing data a bit less useful).
Of course, Virtual NanoLab can read the data and plot it, but what if you want the actual data, the raw numbers? That is, the data you had access to before you put it into the VNL file (typically via the
toArray() method on the data object, e.g. the transmission spectrum).
Well, it turns out that the vnl files have a rather simple but undocumented structure; they are actually just
Python zipfiles, and the data is stored in nested dicts with quite obvious labels! Therefore, it's relatively simple to extract the data, as long as you know what you are doing.
Disclaimer: The scripts below use undocumented features, and may not work in future (and/or some old) releases of ATK.
It's best to do some of these operations in interactive mode, but there is an initial part, which is in the attached script. Download it and run it as
atk -i extract_from_vnl_file.py
Note the "-i" option; this will cause ATK to execute the script and then remain in interactive mode. The script will ask for the filename (because it cannot be given as a script parameter when you want to run in interactive mode); be sure to specify it with full path if it's not in the current directory. (On most platforms you can use the Tab key to complete the file name!)
At this point the script has created a variable (a dictionary) called
samples which contains all the data. In this top-level dict, the keys correspond to the
sample names. You can list the sample names:
Let us assume that the sample we are interested in is called "mySample". To drill down to the data, give the command
data = samples['mySample']['NanoLanguage']
Now, you can see which data has been stored on this sample:
Let us assume that we are looking to extract a transmission spectrum. In that case, you will hopefully see (perhaps among many other things) a key called
"Transmission Spectrum Transmission Spectrum" in the printed list. However, it depends a bit on the version of ATK you used to create the VNL file. In some older versions it's just "Transmission Spectrum" and in some really old ones it might even be "TransmissionSpectrum". So, it's best to inspect the data to be sure!
Now we can extract the data:
trans = data["Transmission Spectrum Transmission Spectrum"]
By typing "trans" and hitting the Tab key, we now find that the so-created "trans" data object has several methods and properties. (You can also give the command
to see the list.
What we are interested in here are the energies E and the values of the transmission at these energies, T(E). Here's how to access it:
E = t.energy()._dataarray_
T = t.average_transmission()
And now we can just print the transmission spectrum (or do whatever you want with it):
for i in range(len(E)):
print E[i],T[i]
Note that if the calculation was spin-polarized, the transmission has a bit different shape.
Using the general method outlined above it should be possible to extract any kind of data stored in a VNL file. Do note, however, that each specific data type is stored in different ways, and you have to figure out the (undocumented) methods and properties for each one by using the "dir()" command quite a lot...
To summarize, here is a complete script that extracts and prints the transmission spectrum from a VNL file, by asking the user for the file and sample name (this script is also attached to this post as
extract_transmission_from_vnl_file.py):
import zipfile, cPickle, sys
filename = raw_input('Please enter VNL file name: ')
try:
f = zipfile.ZipFile(filename,'r')
except:
print 'Unable to locate VNL file "%s"' % filename
sys.exit(1)
# Restore the samples from the VNL file into a dict
samples = {}
for zinfo in f.infolist():
s = f.read(zinfo.filename)
try:
obj = cPickle.loads(s)
samples[obj.name()] = {}
for h in obj.history():
samples[obj.name()][h.name] = h.resultsample.properties()
except:
pass
print 'The following samples are present in this VNL file:'
print samples.keys()
sname = raw_input('Please enter sample name to extract (default=first sample): ')
if sname.strip()=="":
data = samples[samples.keys()[0]]['NanoLanguage']
else:
data = samples[sname]['NanoLanguage']
# Some older versions used "Transmission Spectrum" or "TransmissionSpectrum"
trans = data['Transmission Spectrum Transmission Spectrum']
print 'Energy (eV)\tTotal transmission'
print '----------------------------------'
energies = trans.energy()._dataarray_
# Check for energy unit, if you want to be sure
# e_unit = t.energy().units()
T = trans.average_transmission()
for i in range(len(energies)):
print '%g\t%g' % (energies[i],T[i])