Difference between revisions of "CompSciWeek13"
(Created page with "= Numerical Integration = * The tinkerbell attractor ** Implementations in OpenOffice Spreadsheet, GNU ODE, and Python ** Perturbed initial conditions, Lyapunov exponents, and la…") |
m (→Python Integrator) |
||
(13 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | = Numerical Integration = |
+ | = Numerical Integration + Binary Output Format = |
− | * |
+ | * Van der Pol Oscillator: <math>\ddot u - \mu (1-u^2) \dot u + u = 0</math> |
** Implementations in OpenOffice Spreadsheet, GNU ODE, and Python |
** Implementations in OpenOffice Spreadsheet, GNU ODE, and Python |
||
** Perturbed initial conditions, Lyapunov exponents, and large deviation principles |
** Perturbed initial conditions, Lyapunov exponents, and large deviation principles |
||
* Working well with others: text |
* Working well with others: text |
||
* Working with machines: binary |
* Working with machines: binary |
||
+ | ** This is preferable when you have lots and lots of data |
||
+ | ** The relevant numpy methods are x.tofile("file") and x = fromfile("file") -- but save("file", x) and x = load("file") are preferred |
||
** inspecting binary formats with od |
** inspecting binary formats with od |
||
+ | * [[Media:Integrate.pdf|Lecture Slides]] |
||
+ | |||
+ | === GNU ODE Integrator === |
||
+ | |||
+ | '''vanderpol.ode''' |
||
+ | |||
+ | <source lang="haskell"> |
||
+ | mu = %MU |
||
+ | |||
+ | u = 1.0 |
||
+ | y = 0.0 |
||
+ | |||
+ | u' = y |
||
+ | y' = mu*(1-u*u)*y - u |
||
+ | |||
+ | print t, u, y, y! every 10 from 50 |
||
+ | step 0, 100 |
||
+ | </source> |
||
+ | |||
+ | You can do the substitution with sed and run all dynamics with: |
||
+ | |||
+ | for((i=0;i<10;i++)); do |
||
+ | sed -e "s|%MU|$i|" vanderpol.ode >vanderpol-$i.ode |
||
+ | ode -f vanderpol-$i.ode >out-$i.dat </dev/null |
||
+ | done |
||
+ | |||
+ | === Plotting with Gnuplot === |
||
+ | |||
+ | <source lang="gnuplot"> |
||
+ | set term postscript enh color lw 3 "Times-Roman" 28 |
||
+ | set out 'van.eps' |
||
+ | |||
+ | set xlabel "u" |
||
+ | set ylabel "y" |
||
+ | plot 'out-0.dat' u 2:3 w l title "0", \ |
||
+ | 'out-1.dat' u 2:3 w l title "1", \ |
||
+ | 'out-4.dat' u 2:3 w l title "{/Symbol m} = 4" |
||
+ | </source> |
||
+ | |||
+ | Run with: |
||
+ | |||
+ | gnuplot plot_van.gplot |
||
+ | |||
+ | === Python Integrator === |
||
+ | |||
+ | First, form the heart of the algorithm: |
||
+ | <source lang="python"> |
||
+ | def step(N=1): |
||
+ | for i in xrange(N): |
||
+ | v += (mu*(1.0-x**2)*v - x) * dt |
||
+ | x += v * dt |
||
+ | </source> |
||
+ | Note that this will work if x and v are vectors as well as scalars. |
||
+ | That means we can run a bunch of trajectories with different initial starting points |
||
+ | in one fell swoop. |
||
+ | |||
+ | Next, wrap it inside a class: |
||
+ | <source lang="python"> |
||
+ | class State: |
||
+ | def __init__(self, x, v, mu, dt): |
||
+ | assert x.shape == v.shape |
||
+ | self.mu = mu |
||
+ | self.dt = dt |
||
+ | self.x = x |
||
+ | self.v = v |
||
+ | def state(self, N=1): |
||
+ | # must change all variables (e.g. "name") to "self.name" |
||
+ | </source> |
||
+ | |||
+ | Next, instantiate and run the class: |
||
+ | |||
+ | <source lang="python"> |
||
+ | st = State(5.0, 1.0, 2.0, 0.01) |
||
+ | st.step() |
||
+ | print st.x |
||
+ | st.step() |
||
+ | print st.x |
||
+ | </source> |
||
+ | |||
+ | Next, add a nice printing function to "print the state," |
||
+ | <source lang="python"> |
||
+ | def __str__(self): |
||
+ | s = "" |
||
+ | for x,v in zip(self.x, self.v): |
||
+ | s += " %f %f"%(x, v) |
||
+ | return s |
||
+ | </source> |
||
+ | This prints (x1 v1 x2 v2 ...) in a single, long line. |
||
+ | |||
+ | OK, so now we're ready to run lots of tests. Let's |
||
+ | lift the python program to a command-line program. |
||
+ | Add this to the header: |
||
+ | <source lang="python"> |
||
+ | #!/usr/bin/env python |
||
+ | |||
+ | import sys |
||
+ | from numpy import * |
||
+ | from numpy.random import standard_normal |
||
+ | norm = standard_normal |
||
+ | </source> |
||
+ | |||
+ | Add this to the end of the file: |
||
+ | <source lang="python"> |
||
+ | def main(argv): |
||
+ | print argv |
||
+ | |||
+ | if __name__=="__main__": |
||
+ | main(sys.argv) |
||
+ | </source> |
||
+ | |||
+ | From the shell, run |
||
+ | <source lang="bash"> |
||
+ | chmod +x vanderpol.py |
||
+ | ./vanderpol.py a test argument |
||
+ | </source> |
||
+ | |||
+ | Note that you get to provide parameters to your program at the command-line. |
||
+ | Unfortunately, they all have type str. Let's formalize them, |
||
+ | <source lang="python"> |
||
+ | def main(argv): |
||
+ | assert len(argv) == 5, "Usage: %s x0 p0 R mu"%(argv[0]) |
||
+ | x0, p0, R, mu = map(float, argv[1:5]) |
||
+ | st = State(x0,p0,mu,0.01) |
||
+ | for i in range(500): |
||
+ | st.step(10) |
||
+ | print st |
||
+ | </source> |
||
+ | |||
+ | Finally, we have a new tool that can be run to generate reproducible simulations |
||
+ | of the van der Pol oscillator. Next, we need to consider how to store |
||
+ | the data it generates for later analysis and use. |
||
+ | |||
+ | Here's an example using a 500x2x5 tensor: |
||
+ | <source lang="python"> |
||
+ | T = zeros((500,2,5)) # steps by (x or v) by points |
||
+ | for i in range(500): |
||
+ | st.step(10) |
||
+ | T[i,0] = st.x |
||
+ | T[i,1] = st.v |
||
+ | </source> |
||
+ | |||
+ | This can be "flattened" to a 500x10 tensor, |
||
+ | <source lang="python"> |
||
+ | T = reshape(T, (500,10)) # or reshape(T, (-1,10)) "figures out" the 500 size |
||
+ | </source> |
||
+ | |||
+ | === Working with binary === |
||
+ | Example: [http://man7.org/linux/man-pages/man5/elf.5.html ELF] header |
||
+ | |||
+ | od -t x1 -t c -N 8 /bin/bash |
||
+ | |||
+ | Binary comes in lots of units |
||
+ | |||
+ | |||
+ | {| div class="wikitable" |
||
+ | ! 8 bits |
||
+ | ! = 1 byte |
||
+ | |- |
||
+ | ! 4 bits |
||
+ | ! = 1 nibble |
||
+ | |- |
||
+ | ! 1 byte |
||
+ | ! = 1 ascii character |
||
+ | |- |
||
+ | ! 2 bytes |
||
+ | ! = 1 short = 1 word |
||
+ | |- |
||
+ | ! 4 bytes |
||
+ | ! = 1 32-bit int = 1 float |
||
+ | |- |
||
+ | ! 8 bytes |
||
+ | ! = 1 64-bit int = 1 double = 1 float complex |
||
+ | |- |
||
+ | ! 16 bytes |
||
+ | ! = 1 long double = 1 double complex |
||
+ | |} |
||
+ | |||
+ | Byte ordering on most modern 64-bit processors is little-endian (Intel, AMD). For more info, see [http://betterexplained.com/articles/understanding-big-and-little-endian-byte-order/]. |
||
+ | |||
+ | In an imaginary system where base 10 numbers are encoded by 4-bit nibbles, a 4-digit representation of the number 123 is |
||
+ | |||
+ | 3 = 0011 |
||
+ | 2 = 0010 |
||
+ | 1 = 0001 |
||
+ | 0 = 0000 |
||
+ | |||
+ | The binary together would read: |
||
+ | |||
+ | 0011 0010 0001 0000 |
||
+ | |||
+ | Since we have to use 4 digits, the most significant digit is set to all zeros, and goes last. The little end (least significant byte) goes first. Notice that within the 4-bit nibbles, the least-significant bit is still on the right. So the number is encoded using this left-to right (within a digit) and bottom to top (digits within a word) order. |
||
+ | |||
+ | Real binary encoding is just like the above, except that each 'digit' is a byte, so every 8 bits are in order, but the bytes are reversed. |
||
= Basis Functions = |
= Basis Functions = |
||
Line 11: | Line 206: | ||
* Representing the differentiation operator |
* Representing the differentiation operator |
||
* Solving PDEs using the implicit method |
* Solving PDEs using the implicit method |
||
+ | * [[Media:Basis.pdf|Lecture Slides]] |
Latest revision as of 11:00, 6 April 2016
Contents
Numerical Integration + Binary Output Format
- Van der Pol Oscillator: <math>\ddot u - \mu (1-u^2) \dot u + u = 0</math>
- Implementations in OpenOffice Spreadsheet, GNU ODE, and Python
- Perturbed initial conditions, Lyapunov exponents, and large deviation principles
- Working well with others: text
- Working with machines: binary
- This is preferable when you have lots and lots of data
- The relevant numpy methods are x.tofile("file") and x = fromfile("file") -- but save("file", x) and x = load("file") are preferred
- inspecting binary formats with od
- Lecture Slides
GNU ODE Integrator
vanderpol.ode
<source lang="haskell"> mu = %MU
u = 1.0 y = 0.0
u' = y y' = mu*(1-u*u)*y - u
print t, u, y, y! every 10 from 50 step 0, 100 </source>
You can do the substitution with sed and run all dynamics with:
for((i=0;i<10;i++)); do sed -e "s|%MU|$i|" vanderpol.ode >vanderpol-$i.ode ode -f vanderpol-$i.ode >out-$i.dat </dev/null done
Plotting with Gnuplot
<source lang="gnuplot"> set term postscript enh color lw 3 "Times-Roman" 28 set out 'van.eps'
set xlabel "u" set ylabel "y" plot 'out-0.dat' u 2:3 w l title "0", \
'out-1.dat' u 2:3 w l title "1", \ 'out-4.dat' u 2:3 w l title "{/Symbol m} = 4"
</source>
Run with:
gnuplot plot_van.gplot
Python Integrator
First, form the heart of the algorithm: <source lang="python"> def step(N=1):
for i in xrange(N): v += (mu*(1.0-x**2)*v - x) * dt x += v * dt
</source> Note that this will work if x and v are vectors as well as scalars. That means we can run a bunch of trajectories with different initial starting points in one fell swoop.
Next, wrap it inside a class: <source lang="python"> class State:
def __init__(self, x, v, mu, dt): assert x.shape == v.shape self.mu = mu self.dt = dt self.x = x self.v = v def state(self, N=1):
- must change all variables (e.g. "name") to "self.name"
</source>
Next, instantiate and run the class:
<source lang="python"> st = State(5.0, 1.0, 2.0, 0.01) st.step() print st.x st.step() print st.x </source>
Next, add a nice printing function to "print the state," <source lang="python">
def __str__(self): s = "" for x,v in zip(self.x, self.v): s += " %f %f"%(x, v) return s
</source> This prints (x1 v1 x2 v2 ...) in a single, long line.
OK, so now we're ready to run lots of tests. Let's lift the python program to a command-line program. Add this to the header: <source lang="python">
- !/usr/bin/env python
import sys from numpy import * from numpy.random import standard_normal norm = standard_normal </source>
Add this to the end of the file: <source lang="python"> def main(argv):
print argv
if __name__=="__main__":
main(sys.argv)
</source>
From the shell, run <source lang="bash"> chmod +x vanderpol.py ./vanderpol.py a test argument </source>
Note that you get to provide parameters to your program at the command-line. Unfortunately, they all have type str. Let's formalize them, <source lang="python"> def main(argv):
assert len(argv) == 5, "Usage: %s x0 p0 R mu"%(argv[0]) x0, p0, R, mu = map(float, argv[1:5]) st = State(x0,p0,mu,0.01) for i in range(500): st.step(10) print st
</source>
Finally, we have a new tool that can be run to generate reproducible simulations of the van der Pol oscillator. Next, we need to consider how to store the data it generates for later analysis and use.
Here's an example using a 500x2x5 tensor: <source lang="python"> T = zeros((500,2,5)) # steps by (x or v) by points for i in range(500):
st.step(10) T[i,0] = st.x T[i,1] = st.v
</source>
This can be "flattened" to a 500x10 tensor, <source lang="python"> T = reshape(T, (500,10)) # or reshape(T, (-1,10)) "figures out" the 500 size </source>
Working with binary
Example: ELF header
od -t x1 -t c -N 8 /bin/bash
Binary comes in lots of units
8 bits | = 1 byte |
---|---|
4 bits | = 1 nibble |
1 byte | = 1 ascii character |
2 bytes | = 1 short = 1 word |
4 bytes | = 1 32-bit int = 1 float |
8 bytes | = 1 64-bit int = 1 double = 1 float complex |
16 bytes | = 1 long double = 1 double complex |
Byte ordering on most modern 64-bit processors is little-endian (Intel, AMD). For more info, see [1].
In an imaginary system where base 10 numbers are encoded by 4-bit nibbles, a 4-digit representation of the number 123 is
3 = 0011 2 = 0010 1 = 0001 0 = 0000
The binary together would read:
0011 0010 0001 0000
Since we have to use 4 digits, the most significant digit is set to all zeros, and goes last. The little end (least significant byte) goes first. Notice that within the 4-bit nibbles, the least-significant bit is still on the right. So the number is encoded using this left-to right (within a digit) and bottom to top (digits within a word) order.
Real binary encoding is just like the above, except that each 'digit' is a byte, so every 8 bits are in order, but the bytes are reversed.
Basis Functions
- Constructing B-splines - tensor method
- Representing the differentiation operator
- Solving PDEs using the implicit method
- Lecture Slides