Pythonic Virtual Machine
3d FM-AFM tutorials

Running a full FM-AFM simulation of NaCl

Now for a full simulation using most of the things you have learned in the past few tutorials so the explanation will be more brief. Definitely do not use this tutorial as a starting point, it is recommended that you have went through the previous tutorials first.

As always lets add our mandatory modules, including the phase lock loop (PLL) composite circuit that is required in AFM setups;

1 from vafmcircuits import Machine
2 from customs import *

Lets initialise our machine;

1 machine = Machine(machine=None, name='machine', dt=5.0e-8)

Lets add our Cantilever circuit, the parameters are described in the documentation but for now lets use these values;

1 canti = machine.AddCircuit(type='Cantilever',name='canti', startingz=0.5,Q=10000, k=167.0, f0=150000, pushed=True)

Since we need to be able to measure amplitude we should include the amplitude detector composite circuit;

1 machine.AddCircuit(type="Machine",name='amp', fcut=[10000], assembly=aAMPD, pushed=True)

We need to know just how much we must excite the cantilever so we can do this using a PI circuit;

1 machine.AddCircuit(type='PI', name='agc', Kp=1.1, Ki=800, set=1, pushed=True)

It often safe practice to limit the agc signal so it doesn't get to high or negative so to do this we will implement a limiter circuit.

1 machine.AddCircuit(type="limiter",name='agclim', min=0,max=10, pushed=True)

The most important part of an AFM set up is the PLL (Phase lock loop) as this is the device that actually gives us the change in frequency. Again we have a PLL composite circuit all set up already so simply follow the parameters given below;

1 machine.AddCircuit(type="Machine",name='pll', fcut=1000, assembly=aPLL, filters=[10000,5000,2000], gain=600.0, f0=150000, Kp=0.5, Ki=700, pushed=True)

We need the excitation signal to be off phase by pi /2. Since the output of the pll will be out of phase by -pi /2 (a cosine output wave compared to a sine input wave), so we will invert the cos wave in order to give us a phase shift of pi /2).

1 machine.AddCircuit(type='opMul',name='pllinv',in2=-1, pushed=True)

in order for us to excite the cantilever we must multiply the output of the PLL with the output of the PI circuit to ensure we get an appropriate excitation circuit, hence we must add a multiplication circuit;

1 machine.AddCircuit(type='opMul',name='exc', pushed=True)

We need to be able to move our cantilever so lets add the scanner circuit;

1 scanner = machine.AddCircuit(type='Scanner',name='scan', Process = machine, pushed=True)

We have a 3d force field for the NaCl included in the tutorial, the details of how to add an interpolation circuit was covered in this tutorial so I will simply state what is required here. One thing to note is the ForceMultiplier parameter this allows you to change the units of your force field to what ever it is you require;

1 inter = machine.AddCircuit(type='i3Dlin',name='inter', components=3, pushed=True)
2 inter.Configure(steps=[0.705,0.705,0.1], npoints=[8,8,201])
3 inter.Configure(pbc=[True,True,False])
4 inter.Configure(ForceMultiplier=1e10)
5 inter.ReadData('NaClforces.dat')

We require an output circuit this is set up in the same way as as before, this time the channels we will register are "x" , "y" and the change in frequency "df".

1 imager = machine.AddCircuit(type='output',name='image',file='test.dat', dump=0)
2 imager.Register("scan.x","scan.y","pll.df")

So we have added all the circuits we need for this FM-AFM setup so lets connect our circuits now. so lets hook up or x and y channel of the scanner to the x and y channel of the interpolation circuit;

1 machine.Connect("scan.x" , "inter.x")
2 machine.Connect("scan.y" , "inter.y")

The z channel is a little more involved since the cantilever oscillates in that dimension we must connect the absolute position (position of the holder + oscillation of the cantilever) of the cantilever, so firstly lets connect the scanners z channel to the holder position of the cantilever;

1 machine.Connect("scan.z" , "canti.holderz")

Next lets connect the absolute position of the cantilever (zabs) to the interpolation circuit, hence giving us the force where the tip is;

1 machine.Connect("canti.zabs" , "inter.z")

now lets connect the third force component of the force field (the z component) to the force channel of the cantilever;

1 machine.Connect("inter.F3" , "canti.fz")

So we need to measure the amplitude of the tip so lets connect the tip position to our amplitude detector;

1 machine.Connect('canti.ztip','amp.signal')

So the amplitude detector is capable of outputting the amplitude of the wave or a normalised version of that wave. Since we need to know but how much to excite the wave by lets connect the amplitude to the PI circuit so we can measure that;

1 machine.Connect('amp.amp','agc.signal')

So now we have to hook up our pll circuit, the pll must have a feedback by using the cos output of the pll and have the normalised cantilever as an input

1 machine.Connect('amp.norm','pll.signal1')
2 machine.Connect('pll.cos","pll.signal2')

So now we can multiply the output from the PI circuit and the cos output of the pll circuit in order to create an excitation circuit and then connect this signal to the cantilever excitation channel;

1 machine.Connect('agc.out','agclim.signal')
2 machine.Connect('agclim.out','exc.in1')
3 machine.Connect('pll.cos','pllinv.in1')
4 machine.Connect('pllinv.out','exc.in2')

Lets also connect the scanner record channel to the output recording channel;

1 machine.Connect("scan.record","image.record")

Now we have connected all our circuits and all that is left is to issue commands to the scanner in order to move the cantilever; Lets start by placing our cantilever at position 0,0,15 , please note that the distances are in angstroms since the force field is given in angstroms, also lets wait for 0.5 seconds;

1 scanner.Place(x=0,y=0,z=15)
2 machine.Wait(0.5)

Next lets move scanner down by 11 angstroms and have it wait for 1 seconds this will allow the pll to settle down before we start scanning;

1 scanner.Move(x=0,y=0,z=-11)
2 machine.Wait(1)

Lets now set up our ScanArea function like we did in this tutorial, except this time we want 64 points per line and 64 lines over an image area of 11.68 by 11.68 angstroms. If you are using gnuplot leave the blanklines as True but if you choose to use another plotting program that doesn't use the blank lines feel free to set it to False, finally use the ScanArea() function to begin your scan.

1 scanner.Recorder = imager
2 scanner.BlankLines = True
3 scanner.Resolution = [20,20]
4 scanner.ImageArea(11.28,11.28)
5 scanner.ScanArea()

So the final input file should look like this;

1 #!/usr/bin/env python
2 from vafmcircuits import Machine
3 from customs_pll import *
4 
5 
6 machine = Machine(machine=None, name='machine', dt=5.0e-8)
7 
8 
9 canti = machine.AddCircuit(type='Cantilever',name='canti', startingz=0.5,Q=10000, k=167.0, f0=150000, pushed=True)
10 
11 
12 machine.AddCircuit(type="Machine",name='amp', fcut=[10000], assembly=aAMPD, pushed=True)
13 
14 machine.AddCircuit(type='PI', name='agc', Kp=1.1, Ki=800, set=1, pushed=True)
15 machine.AddCircuit(type="limiter",name='agclim', min=0,max=10, pushed=True)
16 
17 machine.AddCircuit(type="Machine",name='pll', fcut=1000, assembly=aPLL, filters=[10000,5000,2000], gain=600.0, f0=150000, Kp=0.5, Ki=700, pushed=True)
18 
19 machine.AddCircuit(type='opMul',name='pllinv',in2=-1, pushed=True)
20 machine.AddCircuit(type='opMul',name='exc', pushed=True)
21 
22 scanner = machine.AddCircuit(type='Scanner',name='scan', Process = machine, pushed=True)
23 
24 
25 inter = machine.AddCircuit(type='i3Dlin',name='inter', components=3, pushed=True)
26 inter.Configure(steps=[0.705,0.705,0.1], npoints=[8,8,201])
27 inter.Configure(pbc=[True,True,False])
28 inter.Configure(ForceMultiplier=1e10)
29 inter.ReadData('NaClforces.dat')
30 
31 
32 
33 
34 
35 #Outputs
36 out1 = machine.AddCircuit(type='output',name='output',file='testafm.out', dump=2)
37 out1.Register('global.time', 'canti.zabs','amp.norm','pll.cos','pll.sin','exc.in2')
38 out1.Stop()
39 
40 out2 = machine.AddCircuit(type='output',name='output2',file='testafm2.out', dump=10000)
41 out2.Register('global.time', 'canti.ztip','agc.out','pll.df',"canti.fz")
42 out2.Stop()
43 
44 #Imaging output
45 imager = machine.AddCircuit(type='output',name='image',file='NaCl.dat', dump=0)
46 imager.Register("scan.x","scan.y","pll.df")
47 
48 
49 #feed x and y to interpolation
50 machine.Connect("scan.x" , "inter.x")
51 machine.Connect("scan.y" , "inter.y")
52 machine.Connect("scan.z" , "canti.holderz")
53 machine.Connect("canti.zabs" , "inter.z")
54 
55 #Force
56 machine.Connect("inter.F3" , "canti.fz")
57 
58 machine.Connect('canti.ztip','amp.signal')
59 machine.Connect('amp.amp','agc.signal')
60 machine.Connect('amp.norm','pll.signal1')
61 machine.Connect('pll.cos','pll.signal2')
62 
63 machine.Connect('agc.out','agclim.signal')
64 machine.Connect('agclim.out','exc.in1')
65 machine.Connect('pll.cos','pllinv.in1')
66 machine.Connect('pllinv.out','exc.in2')
67 
68 machine.Connect('exc.out','canti.exciter')
69 
70 machine.Connect("scan.record","image.record")
71 
72 
73 
74 
75 scanner.Place(x=0,y=0,z=15)
76 machine.Wait(0.5)
77 
78 scanner.Move(x=0,y=0,z=-11)
79 machine.Wait(1)
80 
81 scanner.Recorder = imager
82 scanner.BlankLines = True
83 #resolution of the image [# points per line, # lines]
84 scanner.Resolution = [20,20]
85 scanner.ImageArea(11.28,11.28)
86 #scan
87 scanner.ScanArea()

This scan will most likely take a long time you can reduce the time it will take by altering the resolution parameter. After it has finished running plot an intensity plot, if you are using gnuplot you can use the following commands;

1 set pm3d
2 set size square
3 set palette rgbformula 34,35,36
4 sp "NaCl.dat" using 1:2:3

Your results should look similar to the image below;


Documentation for pyVAFM
Generated on Wed Feb 8 2017 10:13:49 for pyVAFM by doxygen 1.8.9.1